@isograph/react 0.0.0-main-f524690b → 0.0.0-main-f49c67bb

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/cache.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { ItemCleanupPair, ParentCache } from '@isograph/react-disposable-state';
2
2
  import { PromiseWrapper } from './PromiseWrapper';
3
3
  import { IsographEntrypoint, NormalizationLinkedField, NormalizationScalarField, ReaderLinkedField, ReaderScalarField } from './index';
4
+ import { type IsographEnvironment } from './context';
4
5
  declare global {
5
6
  interface Window {
6
7
  __LOG: boolean;
@@ -13,25 +14,8 @@ declare global {
13
14
  */
14
15
  export declare function stableCopy<T>(value: T): T;
15
16
  type IsoResolver = IsographEntrypoint<any, any, any>;
16
- export declare function getOrCreateCacheForArtifact<T>(artifact: IsographEntrypoint<any, any, T>, variables: object): ParentCache<PromiseWrapper<T>>;
17
- declare let network: ((queryText: string, variables: object) => Promise<any>) | null;
18
- export declare function setNetwork(newNetwork: typeof network): void;
19
- export declare function makeNetworkRequest<T>(artifact: IsoResolver, variables: object): ItemCleanupPair<PromiseWrapper<T>>;
20
- export type Link = {
21
- __link: DataId;
22
- };
23
- export type DataTypeValue = undefined | number | boolean | string | null | Link | DataTypeValue[];
24
- export type StoreRecord = {
25
- [index: DataId | string]: DataTypeValue;
26
- id?: DataId;
27
- };
28
- export type DataId = string;
29
- export declare const ROOT_ID: DataId & '__ROOT';
30
- export declare function getStore(): {
31
- [index: string]: StoreRecord | null;
32
- __ROOT: StoreRecord;
33
- };
34
- export declare function clearStore(): void;
17
+ export declare function getOrCreateCacheForArtifact<T>(environment: IsographEnvironment, artifact: IsographEntrypoint<any, any, T>, variables: object): ParentCache<PromiseWrapper<T>>;
18
+ export declare function makeNetworkRequest<T>(environment: IsographEnvironment, artifact: IsoResolver, variables: object): ItemCleanupPair<PromiseWrapper<T>>;
35
19
  export declare function subscribe(callback: () => void): () => void;
36
20
  export declare function onNextChange(): Promise<void>;
37
21
  export declare function getParentRecordKey(astNode: NormalizationLinkedField | NormalizationScalarField | ReaderLinkedField | ReaderScalarField, variables: {
package/dist/cache.js CHANGED
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SECOND_SPLIT_KEY = exports.FIRST_SPLIT_KEY = exports.getParentRecordKey = exports.onNextChange = exports.subscribe = exports.clearStore = exports.getStore = exports.ROOT_ID = exports.makeNetworkRequest = exports.setNetwork = exports.getOrCreateCacheForArtifact = exports.stableCopy = void 0;
3
+ exports.SECOND_SPLIT_KEY = exports.FIRST_SPLIT_KEY = exports.getParentRecordKey = exports.onNextChange = exports.subscribe = exports.makeNetworkRequest = exports.getOrCreateCacheForArtifact = exports.stableCopy = void 0;
4
4
  const react_disposable_state_1 = require("@isograph/react-disposable-state");
5
5
  const PromiseWrapper_1 = require("./PromiseWrapper");
6
+ const context_1 = require("./context");
6
7
  const cache = {};
7
8
  function getOrCreateCache(index, factory) {
8
9
  if (typeof window !== 'undefined' && window.__LOG) {
@@ -39,30 +40,23 @@ function stableCopy(value) {
39
40
  return stable;
40
41
  }
41
42
  exports.stableCopy = stableCopy;
42
- function getOrCreateCacheForArtifact(artifact, variables) {
43
+ function getOrCreateCacheForArtifact(environment, artifact, variables) {
43
44
  const cacheKey = artifact.queryText + JSON.stringify(stableCopy(variables));
44
- const factory = () => makeNetworkRequest(artifact, variables);
45
+ const factory = () => makeNetworkRequest(environment, artifact, variables);
45
46
  return getOrCreateCache(cacheKey, factory);
46
47
  }
47
48
  exports.getOrCreateCacheForArtifact = getOrCreateCacheForArtifact;
48
- let network;
49
- // This is a hack until we store this in context somehow
50
- function setNetwork(newNetwork) {
51
- network = newNetwork;
52
- }
53
- exports.setNetwork = setNetwork;
54
- function makeNetworkRequest(artifact, variables) {
49
+ function makeNetworkRequest(environment, artifact, variables) {
55
50
  if (typeof window !== 'undefined' && window.__LOG) {
56
51
  console.log('make network request', artifact, variables);
57
52
  }
58
- if (network == null) {
59
- throw new Error('Network must be set before makeNetworkRequest is called');
60
- }
61
- const promise = network(artifact.queryText, variables).then((networkResponse) => {
53
+ const promise = environment
54
+ .networkFunction(artifact.queryText, variables)
55
+ .then((networkResponse) => {
62
56
  if (typeof window !== 'undefined' && window.__LOG) {
63
57
  console.log('network response', artifact);
64
58
  }
65
- normalizeData(artifact.normalizationAst, networkResponse.data, variables, artifact.nestedRefetchQueries);
59
+ normalizeData(environment, artifact.normalizationAst, networkResponse.data, variables, artifact.nestedRefetchQueries);
66
60
  return networkResponse.data;
67
61
  });
68
62
  const wrapper = (0, PromiseWrapper_1.wrapPromise)(promise);
@@ -75,27 +69,13 @@ function makeNetworkRequest(artifact, variables) {
75
69
  return response;
76
70
  }
77
71
  exports.makeNetworkRequest = makeNetworkRequest;
78
- exports.ROOT_ID = '__ROOT';
79
- let store = {
80
- __ROOT: {},
81
- };
82
- function getStore() {
83
- return store;
84
- }
85
- exports.getStore = getStore;
86
- function clearStore() {
87
- store = {
88
- __ROOT: {},
89
- };
90
- }
91
- exports.clearStore = clearStore;
92
- function normalizeData(normalizationAst, networkResponse, variables, nestedRefetchQueries) {
72
+ function normalizeData(environment, normalizationAst, networkResponse, variables, nestedRefetchQueries) {
93
73
  if (typeof window !== 'undefined' && window.__LOG) {
94
74
  console.log('about to normalize', normalizationAst, networkResponse, variables);
95
75
  }
96
- normalizeDataIntoRecord(normalizationAst, networkResponse, store.__ROOT, exports.ROOT_ID, variables, nestedRefetchQueries);
76
+ normalizeDataIntoRecord(environment, normalizationAst, networkResponse, environment.store.__ROOT, context_1.ROOT_ID, variables, nestedRefetchQueries);
97
77
  if (typeof window !== 'undefined' && window.__LOG) {
98
- console.log('after normalization', { store });
78
+ console.log('after normalization', { store: environment.store });
99
79
  }
100
80
  callSubscriptions();
101
81
  }
@@ -120,7 +100,7 @@ function callSubscriptions() {
120
100
  /**
121
101
  * Mutate targetParentRecord according to the normalizationAst and networkResponseParentRecord.
122
102
  */
123
- function normalizeDataIntoRecord(normalizationAst, networkResponseParentRecord, targetParentRecord, targetParentRecordId, variables, nestedRefetchQueries) {
103
+ function normalizeDataIntoRecord(environment, normalizationAst, networkResponseParentRecord, targetParentRecord, targetParentRecordId, variables, nestedRefetchQueries) {
124
104
  for (const normalizationNode of normalizationAst) {
125
105
  switch (normalizationNode.kind) {
126
106
  case 'Scalar': {
@@ -128,7 +108,7 @@ function normalizeDataIntoRecord(normalizationAst, networkResponseParentRecord,
128
108
  break;
129
109
  }
130
110
  case 'Linked': {
131
- normalizeLinkedField(normalizationNode, networkResponseParentRecord, targetParentRecord, targetParentRecordId, variables, nestedRefetchQueries);
111
+ normalizeLinkedField(environment, normalizationNode, networkResponseParentRecord, targetParentRecord, targetParentRecordId, variables, nestedRefetchQueries);
132
112
  break;
133
113
  }
134
114
  }
@@ -149,7 +129,7 @@ function normalizeScalarField(astNode, networkResponseParentRecord, targetStoreR
149
129
  /**
150
130
  * Mutate targetParentRecord with a given linked field ast node.
151
131
  */
152
- function normalizeLinkedField(astNode, networkResponseParentRecord, targetParentRecord, targetParentRecordId, variables, nestedRefetchQueries) {
132
+ function normalizeLinkedField(environment, astNode, networkResponseParentRecord, targetParentRecord, targetParentRecordId, variables, nestedRefetchQueries) {
153
133
  const networkResponseKey = getNetworkResponseKey(astNode);
154
134
  const networkResponseData = networkResponseParentRecord[networkResponseKey];
155
135
  const parentRecordKey = getParentRecordKey(astNode, variables);
@@ -165,24 +145,24 @@ function normalizeLinkedField(astNode, networkResponseParentRecord, targetParent
165
145
  const dataIds = [];
166
146
  for (let i = 0; i < networkResponseData.length; i++) {
167
147
  const networkResponseObject = networkResponseData[i];
168
- const newStoreRecordId = normalizeNetworkResponseObject(astNode, networkResponseObject, targetParentRecordId, variables, i, nestedRefetchQueries);
148
+ const newStoreRecordId = normalizeNetworkResponseObject(environment, astNode, networkResponseObject, targetParentRecordId, variables, i, nestedRefetchQueries);
169
149
  dataIds.push({ __link: newStoreRecordId });
170
150
  }
171
151
  targetParentRecord[parentRecordKey] = dataIds;
172
152
  }
173
153
  else {
174
- const newStoreRecordId = normalizeNetworkResponseObject(astNode, networkResponseData, targetParentRecordId, variables, null, nestedRefetchQueries);
154
+ const newStoreRecordId = normalizeNetworkResponseObject(environment, astNode, networkResponseData, targetParentRecordId, variables, null, nestedRefetchQueries);
175
155
  targetParentRecord[parentRecordKey] = {
176
156
  __link: newStoreRecordId,
177
157
  };
178
158
  }
179
159
  }
180
- function normalizeNetworkResponseObject(astNode, networkResponseData, targetParentRecordId, variables, index, nestedRefetchQueries) {
160
+ function normalizeNetworkResponseObject(environment, astNode, networkResponseData, targetParentRecordId, variables, index, nestedRefetchQueries) {
181
161
  var _a;
182
162
  const newStoreRecordId = getDataIdOfNetworkResponse(targetParentRecordId, networkResponseData, astNode, variables, index);
183
- const newStoreRecord = (_a = store[newStoreRecordId]) !== null && _a !== void 0 ? _a : {};
184
- store[newStoreRecordId] = newStoreRecord;
185
- normalizeDataIntoRecord(astNode.selections, networkResponseData, newStoreRecord, newStoreRecordId, variables, nestedRefetchQueries);
163
+ const newStoreRecord = (_a = environment.store[newStoreRecordId]) !== null && _a !== void 0 ? _a : {};
164
+ environment.store[newStoreRecordId] = newStoreRecord;
165
+ normalizeDataIntoRecord(environment, astNode.selections, networkResponseData, newStoreRecord, newStoreRecordId, variables, nestedRefetchQueries);
186
166
  return newStoreRecordId;
187
167
  }
188
168
  function isScalarOrEmptyArray(data) {
@@ -1,6 +1,6 @@
1
1
  /// <reference types="react" />
2
- import { ReaderArtifact, RefetchQueryArtifactWrapper } from './index';
3
- import { DataId } from './cache';
4
- export declare function getOrCreateCachedComponent(root: DataId, componentName: string, readerArtifact: ReaderArtifact<any, any, any>, variables: {
2
+ import { DataId, ReaderArtifact, RefetchQueryArtifactWrapper } from './index';
3
+ import { IsographEnvironment } from '../dist';
4
+ export declare function getOrCreateCachedComponent(environment: IsographEnvironment, root: DataId, componentName: string, readerArtifact: ReaderArtifact<any, any, any>, variables: {
5
5
  [key: string]: string;
6
6
  }, resolverRefetchQueries: RefetchQueryArtifactWrapper[]): import("react").FC<any>;
@@ -4,7 +4,7 @@ exports.getOrCreateCachedComponent = void 0;
4
4
  const index_1 = require("./index");
5
5
  const cache_1 = require("./cache");
6
6
  const cachedComponentsById = {};
7
- function getOrCreateCachedComponent(root, componentName, readerArtifact, variables, resolverRefetchQueries) {
7
+ function getOrCreateCachedComponent(environment, root, componentName, readerArtifact, variables, resolverRefetchQueries) {
8
8
  var _a, _b, _c;
9
9
  const stringifiedArgs = JSON.stringify((0, cache_1.stableCopy)(variables));
10
10
  cachedComponentsById[root] = (_a = cachedComponentsById[root]) !== null && _a !== void 0 ? _a : {};
@@ -14,7 +14,7 @@ function getOrCreateCachedComponent(root, componentName, readerArtifact, variabl
14
14
  byArgs[stringifiedArgs] =
15
15
  (_c = byArgs[stringifiedArgs]) !== null && _c !== void 0 ? _c : (() => {
16
16
  function Component(additionalRuntimeProps) {
17
- const data = (0, index_1.readButDoNotEvaluate)({
17
+ const data = (0, index_1.readButDoNotEvaluate)(environment, {
18
18
  kind: 'FragmentReference',
19
19
  readerArtifact: readerArtifact,
20
20
  root,
@@ -0,0 +1,34 @@
1
+ import { ReactNode } from 'react';
2
+ import * as React from 'react';
3
+ export declare const IsographEnvironmentContext: React.Context<IsographEnvironment | null>;
4
+ export type IsographEnvironment = {
5
+ store: IsographStore;
6
+ networkFunction: IsographNetworkFunction;
7
+ missingFieldHandler: MissingFieldHandler | null;
8
+ };
9
+ export type MissingFieldHandler = (storeRecord: StoreRecord, root: DataId, fieldName: string, arguments_: {
10
+ [index: string]: any;
11
+ } | null, variables: {
12
+ [index: string]: any;
13
+ } | null) => Link | undefined;
14
+ export type IsographNetworkFunction = (queryText: string, variables: object) => Promise<any>;
15
+ export type Link = {
16
+ __link: DataId;
17
+ };
18
+ export type DataTypeValue = undefined | number | boolean | string | null | Link | DataTypeValue[];
19
+ export type StoreRecord = {
20
+ [index: DataId | string]: DataTypeValue;
21
+ id?: DataId;
22
+ };
23
+ export type DataId = string;
24
+ export declare const ROOT_ID: DataId & '__ROOT';
25
+ export type IsographStore = {
26
+ [index: DataId]: StoreRecord | null;
27
+ __ROOT: StoreRecord;
28
+ };
29
+ export type IsographEnvironmentProviderProps = {
30
+ environment: IsographEnvironment;
31
+ children: ReactNode;
32
+ };
33
+ export declare function IsographEnvironmentProvider({ environment, children, }: IsographEnvironmentProviderProps): React.JSX.Element;
34
+ export declare function useIsographEnvironment(): IsographEnvironment;
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.useIsographEnvironment = exports.IsographEnvironmentProvider = exports.ROOT_ID = exports.IsographEnvironmentContext = void 0;
27
+ const react_1 = require("react");
28
+ const React = __importStar(require("react"));
29
+ const cache_1 = require("./cache");
30
+ exports.IsographEnvironmentContext = (0, react_1.createContext)(null);
31
+ exports.ROOT_ID = '__ROOT';
32
+ function IsographEnvironmentProvider({ environment, children, }) {
33
+ const [, setState] = React.useState();
34
+ React.useEffect(() => {
35
+ return (0, cache_1.subscribe)(() => setState({}));
36
+ }, []);
37
+ return (React.createElement(exports.IsographEnvironmentContext.Provider, { value: environment }, children));
38
+ }
39
+ exports.IsographEnvironmentProvider = IsographEnvironmentProvider;
40
+ function useIsographEnvironment() {
41
+ const context = (0, react_1.useContext)(exports.IsographEnvironmentContext);
42
+ if (context == null) {
43
+ throw new Error('Unexpected null environment context. Make sure to render ' +
44
+ 'this component within an IsographEnvironmentProvider component');
45
+ }
46
+ return context;
47
+ }
48
+ exports.useIsographEnvironment = useIsographEnvironment;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import { DataId, StoreRecord, Link } from './cache';
2
- export { setNetwork, makeNetworkRequest, subscribe, DataId, Link, StoreRecord, clearStore, } from './cache';
1
+ import { DataId, IsographEnvironment, Link, StoreRecord } from './context';
2
+ export { makeNetworkRequest, subscribe } from './cache';
3
+ export { IsographEnvironmentContext, ROOT_ID, type DataId, type DataTypeValue, type IsographEnvironment, IsographEnvironmentProvider, type IsographEnvironmentProviderProps, type IsographNetworkFunction, type IsographStore, type Link, type StoreRecord, useIsographEnvironment, } from './context';
3
4
  export { iso } from './iso';
4
5
  export type IsographEntrypoint<TReadFromStore extends Object, TResolverProps, TResolverResult> = {
5
6
  kind: 'Entrypoint';
@@ -102,14 +103,14 @@ type ExtractResolverResult<Type> = Type extends IsographEntrypoint<any, any, inf
102
103
  export declare function useLazyReference<TEntrypoint>(entrypoint: TEntrypoint | ((_: any) => any), variables: object): {
103
104
  queryReference: FragmentReference<ExtractTReadFromStore<TEntrypoint>, ExtractResolverProps<TEntrypoint>, ExtractResolverResult<TEntrypoint>>;
104
105
  };
105
- export declare function read<TReadFromStore extends Object, TResolverProps, TResolverResult>(fragmentReference: FragmentReference<TReadFromStore, TResolverProps, TResolverResult>): TResolverResult;
106
- export declare function readButDoNotEvaluate<TReadFromStore extends Object>(reference: FragmentReference<TReadFromStore, unknown, unknown>): TReadFromStore;
107
- export declare function defaultMissingFieldHandler(storeRecord: StoreRecord, root: DataId, fieldName: string, arguments_: {
106
+ export declare function useRead<TReadFromStore extends Object, TResolverProps, TResolverResult>(fragmentReference: FragmentReference<TReadFromStore, TResolverProps, TResolverResult>): TResolverResult;
107
+ export declare function read<TReadFromStore extends Object, TResolverProps, TResolverResult>(environment: IsographEnvironment, fragmentReference: FragmentReference<TReadFromStore, TResolverProps, TResolverResult>): TResolverResult;
108
+ export declare function readButDoNotEvaluate<TReadFromStore extends Object>(environment: IsographEnvironment, reference: FragmentReference<TReadFromStore, unknown, unknown>): TReadFromStore;
109
+ export declare function defaultMissingFieldHandler(_storeRecord: StoreRecord, _root: DataId, fieldName: string, arguments_: {
108
110
  [index: string]: any;
109
111
  } | null, variables: {
110
112
  [index: string]: any;
111
113
  } | null): Link | undefined;
112
- export declare function setMissingFieldHandler(handler: typeof defaultMissingFieldHandler): void;
113
114
  export type IsographComponentProps<TDataType, TOtherProps = Object> = {
114
115
  data: TDataType;
115
116
  } & TOtherProps;
package/dist/index.js CHANGED
@@ -1,14 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.setMissingFieldHandler = exports.defaultMissingFieldHandler = exports.readButDoNotEvaluate = exports.read = exports.useLazyReference = exports.iso = exports.clearStore = exports.subscribe = exports.makeNetworkRequest = exports.setNetwork = void 0;
3
+ exports.defaultMissingFieldHandler = exports.readButDoNotEvaluate = exports.read = exports.useRead = exports.useLazyReference = exports.iso = exports.useIsographEnvironment = exports.IsographEnvironmentProvider = exports.ROOT_ID = exports.IsographEnvironmentContext = exports.subscribe = exports.makeNetworkRequest = void 0;
4
4
  const cache_1 = require("./cache");
5
5
  const react_disposable_state_1 = require("@isograph/react-disposable-state");
6
6
  const componentCache_1 = require("./componentCache");
7
+ const context_1 = require("./context");
7
8
  var cache_2 = require("./cache");
8
- Object.defineProperty(exports, "setNetwork", { enumerable: true, get: function () { return cache_2.setNetwork; } });
9
9
  Object.defineProperty(exports, "makeNetworkRequest", { enumerable: true, get: function () { return cache_2.makeNetworkRequest; } });
10
10
  Object.defineProperty(exports, "subscribe", { enumerable: true, get: function () { return cache_2.subscribe; } });
11
- Object.defineProperty(exports, "clearStore", { enumerable: true, get: function () { return cache_2.clearStore; } });
11
+ var context_2 = require("./context");
12
+ Object.defineProperty(exports, "IsographEnvironmentContext", { enumerable: true, get: function () { return context_2.IsographEnvironmentContext; } });
13
+ Object.defineProperty(exports, "ROOT_ID", { enumerable: true, get: function () { return context_2.ROOT_ID; } });
14
+ Object.defineProperty(exports, "IsographEnvironmentProvider", { enumerable: true, get: function () { return context_2.IsographEnvironmentProvider; } });
15
+ Object.defineProperty(exports, "useIsographEnvironment", { enumerable: true, get: function () { return context_2.useIsographEnvironment; } });
12
16
  var iso_1 = require("./iso");
13
17
  Object.defineProperty(exports, "iso", { enumerable: true, get: function () { return iso_1.iso; } });
14
18
  function assertIsEntrypoint(value) {
@@ -20,9 +24,10 @@ function assertIsEntrypoint(value) {
20
24
  // We cannot write TEntrypoint extends IsographEntrypoint<never, never, never>, or else
21
25
  // any actual Entrypoint we pass will not be valid.
22
26
  function useLazyReference(entrypoint, variables) {
27
+ const environment = (0, context_1.useIsographEnvironment)();
23
28
  assertIsEntrypoint(entrypoint);
24
29
  // Typechecking fails here... TODO investigate
25
- const cache = (0, cache_1.getOrCreateCacheForArtifact)(entrypoint, variables);
30
+ const cache = (0, cache_1.getOrCreateCacheForArtifact)(environment, entrypoint, variables);
26
31
  // TODO add comment explaining why we never use this value
27
32
  // @ts-ignore
28
33
  const data = (0, react_disposable_state_1.useLazyDisposableState)(cache).state;
@@ -30,18 +35,23 @@ function useLazyReference(entrypoint, variables) {
30
35
  queryReference: {
31
36
  kind: 'FragmentReference',
32
37
  readerArtifact: entrypoint.readerArtifact,
33
- root: cache_1.ROOT_ID,
38
+ root: context_1.ROOT_ID,
34
39
  variables,
35
40
  nestedRefetchQueries: entrypoint.nestedRefetchQueries,
36
41
  },
37
42
  };
38
43
  }
39
44
  exports.useLazyReference = useLazyReference;
40
- function read(fragmentReference) {
45
+ function useRead(fragmentReference) {
46
+ const environment = (0, context_1.useIsographEnvironment)();
47
+ return read(environment, fragmentReference);
48
+ }
49
+ exports.useRead = useRead;
50
+ function read(environment, fragmentReference) {
41
51
  var _a, _b;
42
52
  const variant = fragmentReference.readerArtifact.variant;
43
53
  if (variant.kind === 'Eager') {
44
- const data = readData(fragmentReference.readerArtifact.readerAst, fragmentReference.root, (_a = fragmentReference.variables) !== null && _a !== void 0 ? _a : {}, fragmentReference.nestedRefetchQueries);
54
+ const data = readData(environment, fragmentReference.readerArtifact.readerAst, fragmentReference.root, (_a = fragmentReference.variables) !== null && _a !== void 0 ? _a : {}, fragmentReference.nestedRefetchQueries);
45
55
  if (data.kind === 'MissingData') {
46
56
  throw (0, cache_1.onNextChange)();
47
57
  }
@@ -51,15 +61,15 @@ function read(fragmentReference) {
51
61
  }
52
62
  else if (variant.kind === 'Component') {
53
63
  // @ts-ignore
54
- return (0, componentCache_1.getOrCreateCachedComponent)(fragmentReference.root, variant.componentName, fragmentReference.readerArtifact, (_b = fragmentReference.variables) !== null && _b !== void 0 ? _b : {}, fragmentReference.nestedRefetchQueries);
64
+ return (0, componentCache_1.getOrCreateCachedComponent)(environment, fragmentReference.root, variant.componentName, fragmentReference.readerArtifact, (_b = fragmentReference.variables) !== null && _b !== void 0 ? _b : {}, fragmentReference.nestedRefetchQueries);
55
65
  }
56
66
  // Why can't Typescript realize that this is unreachable??
57
67
  throw new Error('This is unreachable');
58
68
  }
59
69
  exports.read = read;
60
- function readButDoNotEvaluate(reference) {
70
+ function readButDoNotEvaluate(environment, reference) {
61
71
  var _a;
62
- const response = readData(reference.readerArtifact.readerAst, reference.root, (_a = reference.variables) !== null && _a !== void 0 ? _a : {}, reference.nestedRefetchQueries);
72
+ const response = readData(environment, reference.readerArtifact.readerAst, reference.root, (_a = reference.variables) !== null && _a !== void 0 ? _a : {}, reference.nestedRefetchQueries);
63
73
  if (typeof window !== 'undefined' && window.__LOG) {
64
74
  console.log('done reading', { response });
65
75
  }
@@ -71,9 +81,9 @@ function readButDoNotEvaluate(reference) {
71
81
  }
72
82
  }
73
83
  exports.readButDoNotEvaluate = readButDoNotEvaluate;
74
- function readData(ast, root, variables, nestedRefetchQueries) {
75
- var _a, _b, _c, _d;
76
- let storeRecord = (0, cache_1.getStore)()[root];
84
+ function readData(environment, ast, root, variables, nestedRefetchQueries) {
85
+ var _a, _b, _c, _d, _e;
86
+ let storeRecord = environment.store[root];
77
87
  if (storeRecord === undefined) {
78
88
  return { kind: 'MissingData', reason: 'No record for root ' + root };
79
89
  }
@@ -119,7 +129,7 @@ function readData(ast, root, variables, nestedRefetchQueries) {
119
129
  results.push(null);
120
130
  continue;
121
131
  }
122
- const result = readData(field.selections, link.__link, variables, nestedRefetchQueries);
132
+ const result = readData(environment, field.selections, link.__link, variables, nestedRefetchQueries);
123
133
  if (result.kind === 'MissingData') {
124
134
  return {
125
135
  kind: 'MissingData',
@@ -140,6 +150,7 @@ function readData(ast, root, variables, nestedRefetchQueries) {
140
150
  let link = assertLink(value);
141
151
  if (link === undefined) {
142
152
  // TODO make this configurable, and also generated and derived from the schema
153
+ const missingFieldHandler = (_c = environment.missingFieldHandler) !== null && _c !== void 0 ? _c : defaultMissingFieldHandler;
143
154
  const altLink = missingFieldHandler(storeRecord, root, field.fieldName, field.arguments, variables);
144
155
  if (altLink === undefined) {
145
156
  return {
@@ -157,11 +168,11 @@ function readData(ast, root, variables, nestedRefetchQueries) {
157
168
  }
158
169
  }
159
170
  else if (link === null) {
160
- target[(_c = field.alias) !== null && _c !== void 0 ? _c : field.fieldName] = null;
171
+ target[(_d = field.alias) !== null && _d !== void 0 ? _d : field.fieldName] = null;
161
172
  break;
162
173
  }
163
174
  const targetId = link.__link;
164
- const data = readData(field.selections, targetId, variables, nestedRefetchQueries);
175
+ const data = readData(environment, field.selections, targetId, variables, nestedRefetchQueries);
165
176
  if (data.kind === 'MissingData') {
166
177
  return {
167
178
  kind: 'MissingData',
@@ -169,11 +180,11 @@ function readData(ast, root, variables, nestedRefetchQueries) {
169
180
  nestedReason: data,
170
181
  };
171
182
  }
172
- target[(_d = field.alias) !== null && _d !== void 0 ? _d : field.fieldName] = data.data;
183
+ target[(_e = field.alias) !== null && _e !== void 0 ? _e : field.fieldName] = data.data;
173
184
  break;
174
185
  }
175
186
  case 'RefetchField': {
176
- const data = readData(field.readerArtifact.readerAst, root, variables,
187
+ const data = readData(environment, field.readerArtifact.readerAst, root, variables,
177
188
  // Refetch fields just read the id, and don't need refetch query artifacts
178
189
  []);
179
190
  if (typeof window !== 'undefined' && window.__LOG) {
@@ -194,12 +205,12 @@ function readData(ast, root, variables, nestedRefetchQueries) {
194
205
  const refetchQuery = nestedRefetchQueries[refetchQueryIndex];
195
206
  const refetchQueryArtifact = refetchQuery.artifact;
196
207
  const allowedVariables = refetchQuery.allowedVariables;
197
- target[field.alias] = field.readerArtifact.resolver(refetchQueryArtifact, Object.assign(Object.assign({}, data.data), filterVariables(variables, allowedVariables)));
208
+ target[field.alias] = field.readerArtifact.resolver(environment, refetchQueryArtifact, Object.assign(Object.assign({}, data.data), filterVariables(variables, allowedVariables)));
198
209
  }
199
210
  break;
200
211
  }
201
212
  case 'MutationField': {
202
- const data = readData(field.readerArtifact.readerAst, root, variables,
213
+ const data = readData(environment, field.readerArtifact.readerAst, root, variables,
203
214
  // Refetch fields just read the id, and don't need refetch query artifacts
204
215
  []);
205
216
  if (typeof window !== 'undefined' && window.__LOG) {
@@ -220,7 +231,7 @@ function readData(ast, root, variables, nestedRefetchQueries) {
220
231
  const refetchQuery = nestedRefetchQueries[refetchQueryIndex];
221
232
  const refetchQueryArtifact = refetchQuery.artifact;
222
233
  const allowedVariables = refetchQuery.allowedVariables;
223
- target[field.alias] = field.readerArtifact.resolver(refetchQueryArtifact, data.data, filterVariables(variables, allowedVariables));
234
+ target[field.alias] = field.readerArtifact.resolver(environment, refetchQueryArtifact, data.data, filterVariables(variables, allowedVariables));
224
235
  }
225
236
  break;
226
237
  }
@@ -229,7 +240,7 @@ function readData(ast, root, variables, nestedRefetchQueries) {
229
240
  const resolverRefetchQueries = usedRefetchQueries.map((index) => nestedRefetchQueries[index]);
230
241
  const variant = field.readerArtifact.variant;
231
242
  if (variant.kind === 'Eager') {
232
- const data = readData(field.readerArtifact.readerAst, root, variables, resolverRefetchQueries);
243
+ const data = readData(environment, field.readerArtifact.readerAst, root, variables, resolverRefetchQueries);
233
244
  if (data.kind === 'MissingData') {
234
245
  return {
235
246
  kind: 'MissingData',
@@ -242,7 +253,7 @@ function readData(ast, root, variables, nestedRefetchQueries) {
242
253
  }
243
254
  }
244
255
  else if (variant.kind === 'Component') {
245
- target[field.alias] = (0, componentCache_1.getOrCreateCachedComponent)(root, variant.componentName, field.readerArtifact, variables, resolverRefetchQueries);
256
+ target[field.alias] = (0, componentCache_1.getOrCreateCachedComponent)(environment, root, variant.componentName, field.readerArtifact, variables, resolverRefetchQueries);
246
257
  }
247
258
  break;
248
259
  }
@@ -250,16 +261,7 @@ function readData(ast, root, variables, nestedRefetchQueries) {
250
261
  }
251
262
  return { kind: 'Success', data: target };
252
263
  }
253
- let customMissingFieldHandler = null;
254
- function missingFieldHandler(storeRecord, root, fieldName, arguments_, variables) {
255
- if (customMissingFieldHandler != null) {
256
- return customMissingFieldHandler(storeRecord, root, fieldName, arguments_, variables);
257
- }
258
- else {
259
- return defaultMissingFieldHandler(storeRecord, root, fieldName, arguments_, variables);
260
- }
261
- }
262
- function defaultMissingFieldHandler(storeRecord, root, fieldName, arguments_, variables) {
264
+ function defaultMissingFieldHandler(_storeRecord, _root, fieldName, arguments_, variables) {
263
265
  if (fieldName === 'node' || fieldName === 'user') {
264
266
  const variable = arguments_ === null || arguments_ === void 0 ? void 0 : arguments_['id'];
265
267
  const value = variables === null || variables === void 0 ? void 0 : variables[variable];
@@ -270,10 +272,6 @@ function defaultMissingFieldHandler(storeRecord, root, fieldName, arguments_, va
270
272
  }
271
273
  }
272
274
  exports.defaultMissingFieldHandler = defaultMissingFieldHandler;
273
- function setMissingFieldHandler(handler) {
274
- customMissingFieldHandler = handler;
275
- }
276
- exports.setMissingFieldHandler = setMissingFieldHandler;
277
275
  function assertLink(link) {
278
276
  if (Array.isArray(link)) {
279
277
  throw new Error('Unexpected array');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@isograph/react",
3
- "version": "0.0.0-main-f524690b",
3
+ "version": "0.0.0-main-f49c67bb",
4
4
  "description": "Use Isograph with React",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -15,8 +15,8 @@
15
15
  "prepack": "yarn run test && yarn run compile"
16
16
  },
17
17
  "dependencies": {
18
- "@isograph/disposable-types": "0.0.0-main-f524690b",
19
- "@isograph/react-disposable-state": "0.0.0-main-f524690b",
18
+ "@isograph/disposable-types": "0.0.0-main-f49c67bb",
19
+ "@isograph/react-disposable-state": "0.0.0-main-f49c67bb",
20
20
  "react": "^18.2.0"
21
21
  },
22
22
  "devDependencies": {
@@ -15,6 +15,13 @@ import {
15
15
  ReaderScalarField,
16
16
  RefetchQueryArtifactWrapper,
17
17
  } from './index';
18
+ import {
19
+ DataId,
20
+ ROOT_ID,
21
+ StoreRecord,
22
+ Link,
23
+ type IsographEnvironment,
24
+ } from './context';
18
25
 
19
26
  declare global {
20
27
  interface Window {
@@ -67,47 +74,39 @@ export function stableCopy<T>(value: T): T {
67
74
  type IsoResolver = IsographEntrypoint<any, any, any>;
68
75
 
69
76
  export function getOrCreateCacheForArtifact<T>(
77
+ environment: IsographEnvironment,
70
78
  artifact: IsographEntrypoint<any, any, T>,
71
79
  variables: object,
72
80
  ): ParentCache<PromiseWrapper<T>> {
73
81
  const cacheKey = artifact.queryText + JSON.stringify(stableCopy(variables));
74
82
  const factory: Factory<PromiseWrapper<T>> = () =>
75
- makeNetworkRequest<T>(artifact, variables);
83
+ makeNetworkRequest<T>(environment, artifact, variables);
76
84
  return getOrCreateCache<PromiseWrapper<T>>(cacheKey, factory);
77
85
  }
78
86
 
79
- let network: ((queryText: string, variables: object) => Promise<any>) | null;
80
-
81
- // This is a hack until we store this in context somehow
82
- export function setNetwork(newNetwork: typeof network) {
83
- network = newNetwork;
84
- }
85
-
86
87
  export function makeNetworkRequest<T>(
88
+ environment: IsographEnvironment,
87
89
  artifact: IsoResolver,
88
90
  variables: object,
89
91
  ): ItemCleanupPair<PromiseWrapper<T>> {
90
92
  if (typeof window !== 'undefined' && window.__LOG) {
91
93
  console.log('make network request', artifact, variables);
92
94
  }
93
- if (network == null) {
94
- throw new Error('Network must be set before makeNetworkRequest is called');
95
- }
96
-
97
- const promise = network(artifact.queryText, variables).then(
98
- (networkResponse) => {
95
+ const promise = environment
96
+ .networkFunction(artifact.queryText, variables)
97
+ .then((networkResponse) => {
99
98
  if (typeof window !== 'undefined' && window.__LOG) {
100
99
  console.log('network response', artifact);
101
100
  }
102
101
  normalizeData(
102
+ environment,
103
103
  artifact.normalizationAst,
104
104
  networkResponse.data,
105
105
  variables,
106
106
  artifact.nestedRefetchQueries,
107
107
  );
108
108
  return networkResponse.data;
109
- },
110
- );
109
+ });
111
110
 
112
111
  const wrapper = wrapPromise(promise);
113
112
 
@@ -120,48 +119,6 @@ export function makeNetworkRequest<T>(
120
119
  return response;
121
120
  }
122
121
 
123
- export type Link = {
124
- __link: DataId;
125
- };
126
- export type DataTypeValue =
127
- // N.B. undefined is here to support optional id's, but
128
- // undefined should not *actually* be present in the store.
129
- | undefined
130
- // Singular scalar fields:
131
- | number
132
- | boolean
133
- | string
134
- | null
135
- // Singular linked fields:
136
- | Link
137
- // Plural scalar and linked fields:
138
- | DataTypeValue[];
139
-
140
- export type StoreRecord = {
141
- [index: DataId | string]: DataTypeValue;
142
- // TODO __typename?: T, which is restricted to being a concrete string
143
- // TODO this shouldn't always be named id
144
- id?: DataId;
145
- };
146
-
147
- export type DataId = string;
148
-
149
- export const ROOT_ID: DataId & '__ROOT' = '__ROOT';
150
- let store: {
151
- [index: DataId]: StoreRecord | null;
152
- __ROOT: StoreRecord;
153
- } = {
154
- __ROOT: {},
155
- };
156
- export function getStore() {
157
- return store;
158
- }
159
- export function clearStore() {
160
- store = {
161
- __ROOT: {},
162
- };
163
- }
164
-
165
122
  type NetworkResponseScalarValue = string | number | boolean;
166
123
  type NetworkResponseValue =
167
124
  | NetworkResponseScalarValue
@@ -177,6 +134,7 @@ type NetworkResponseObject = {
177
134
  };
178
135
 
179
136
  function normalizeData(
137
+ environment: IsographEnvironment,
180
138
  normalizationAst: NormalizationAst,
181
139
  networkResponse: NetworkResponseObject,
182
140
  variables: Object,
@@ -191,15 +149,16 @@ function normalizeData(
191
149
  );
192
150
  }
193
151
  normalizeDataIntoRecord(
152
+ environment,
194
153
  normalizationAst,
195
154
  networkResponse,
196
- store.__ROOT,
155
+ environment.store.__ROOT,
197
156
  ROOT_ID,
198
157
  variables as any,
199
158
  nestedRefetchQueries,
200
159
  );
201
160
  if (typeof window !== 'undefined' && window.__LOG) {
202
- console.log('after normalization', { store });
161
+ console.log('after normalization', { store: environment.store });
203
162
  }
204
163
  callSubscriptions();
205
164
  }
@@ -228,6 +187,7 @@ function callSubscriptions() {
228
187
  * Mutate targetParentRecord according to the normalizationAst and networkResponseParentRecord.
229
188
  */
230
189
  function normalizeDataIntoRecord(
190
+ environment: IsographEnvironment,
231
191
  normalizationAst: NormalizationAst,
232
192
  networkResponseParentRecord: NetworkResponseObject,
233
193
  targetParentRecord: StoreRecord,
@@ -248,6 +208,7 @@ function normalizeDataIntoRecord(
248
208
  }
249
209
  case 'Linked': {
250
210
  normalizeLinkedField(
211
+ environment,
251
212
  normalizationNode,
252
213
  networkResponseParentRecord,
253
214
  targetParentRecord,
@@ -285,6 +246,7 @@ function normalizeScalarField(
285
246
  * Mutate targetParentRecord with a given linked field ast node.
286
247
  */
287
248
  function normalizeLinkedField(
249
+ environment: IsographEnvironment,
288
250
  astNode: NormalizationLinkedField,
289
251
  networkResponseParentRecord: NetworkResponseObject,
290
252
  targetParentRecord: StoreRecord,
@@ -309,10 +271,11 @@ function normalizeLinkedField(
309
271
 
310
272
  if (Array.isArray(networkResponseData)) {
311
273
  // TODO check astNode.plural or the like
312
- const dataIds = [];
274
+ const dataIds: Link[] = [];
313
275
  for (let i = 0; i < networkResponseData.length; i++) {
314
276
  const networkResponseObject = networkResponseData[i];
315
277
  const newStoreRecordId = normalizeNetworkResponseObject(
278
+ environment,
316
279
  astNode,
317
280
  networkResponseObject,
318
281
  targetParentRecordId,
@@ -325,6 +288,7 @@ function normalizeLinkedField(
325
288
  targetParentRecord[parentRecordKey] = dataIds;
326
289
  } else {
327
290
  const newStoreRecordId = normalizeNetworkResponseObject(
291
+ environment,
328
292
  astNode,
329
293
  networkResponseData,
330
294
  targetParentRecordId,
@@ -339,6 +303,7 @@ function normalizeLinkedField(
339
303
  }
340
304
 
341
305
  function normalizeNetworkResponseObject(
306
+ environment: IsographEnvironment,
342
307
  astNode: NormalizationLinkedField,
343
308
  networkResponseData: NetworkResponseObject,
344
309
  targetParentRecordId: string,
@@ -354,10 +319,11 @@ function normalizeNetworkResponseObject(
354
319
  index,
355
320
  );
356
321
 
357
- const newStoreRecord = store[newStoreRecordId] ?? {};
358
- store[newStoreRecordId] = newStoreRecord;
322
+ const newStoreRecord = environment.store[newStoreRecordId] ?? {};
323
+ environment.store[newStoreRecordId] = newStoreRecord;
359
324
 
360
325
  normalizeDataIntoRecord(
326
+ environment,
361
327
  astNode.selections,
362
328
  networkResponseData,
363
329
  newStoreRecord,
@@ -1,9 +1,11 @@
1
1
  import {
2
+ DataId,
2
3
  ReaderArtifact,
3
4
  RefetchQueryArtifactWrapper,
4
5
  readButDoNotEvaluate,
5
6
  } from './index';
6
- import { DataId, stableCopy } from './cache';
7
+ import { stableCopy } from './cache';
8
+ import { IsographEnvironment } from '../dist';
7
9
 
8
10
  type ComponentName = string;
9
11
  type StringifiedArgs = string;
@@ -13,6 +15,7 @@ const cachedComponentsById: {
13
15
  };
14
16
  } = {};
15
17
  export function getOrCreateCachedComponent(
18
+ environment: IsographEnvironment,
16
19
  root: DataId,
17
20
  componentName: string,
18
21
  readerArtifact: ReaderArtifact<any, any, any>,
@@ -28,7 +31,7 @@ export function getOrCreateCachedComponent(
28
31
  byArgs[stringifiedArgs] ??
29
32
  (() => {
30
33
  function Component(additionalRuntimeProps) {
31
- const data = readButDoNotEvaluate({
34
+ const data = readButDoNotEvaluate(environment, {
32
35
  kind: 'FragmentReference',
33
36
  readerArtifact: readerArtifact,
34
37
  root,
@@ -0,0 +1,90 @@
1
+ import { ReactNode, createContext, useContext } from 'react';
2
+ import * as React from 'react';
3
+ import { subscribe } from './cache';
4
+
5
+ export const IsographEnvironmentContext =
6
+ createContext<IsographEnvironment | null>(null);
7
+
8
+ export type IsographEnvironment = {
9
+ store: IsographStore;
10
+ networkFunction: IsographNetworkFunction;
11
+ missingFieldHandler: MissingFieldHandler | null;
12
+ };
13
+
14
+ export type MissingFieldHandler = (
15
+ storeRecord: StoreRecord,
16
+ root: DataId,
17
+ fieldName: string,
18
+ arguments_: { [index: string]: any } | null,
19
+ variables: { [index: string]: any } | null,
20
+ ) => Link | undefined;
21
+
22
+ export type IsographNetworkFunction = (
23
+ queryText: string,
24
+ variables: object,
25
+ ) => Promise<any>;
26
+
27
+ export type Link = {
28
+ __link: DataId;
29
+ };
30
+ export type DataTypeValue =
31
+ // N.B. undefined is here to support optional id's, but
32
+ // undefined should not *actually* be present in the store.
33
+ | undefined
34
+ // Singular scalar fields:
35
+ | number
36
+ | boolean
37
+ | string
38
+ | null
39
+ // Singular linked fields:
40
+ | Link
41
+ // Plural scalar and linked fields:
42
+ | DataTypeValue[];
43
+
44
+ export type StoreRecord = {
45
+ [index: DataId | string]: DataTypeValue;
46
+ // TODO __typename?: T, which is restricted to being a concrete string
47
+ // TODO this shouldn't always be named id
48
+ id?: DataId;
49
+ };
50
+
51
+ export type DataId = string;
52
+
53
+ export const ROOT_ID: DataId & '__ROOT' = '__ROOT';
54
+
55
+ export type IsographStore = {
56
+ [index: DataId]: StoreRecord | null;
57
+ __ROOT: StoreRecord;
58
+ };
59
+
60
+ export type IsographEnvironmentProviderProps = {
61
+ environment: IsographEnvironment;
62
+ children: ReactNode;
63
+ };
64
+
65
+ export function IsographEnvironmentProvider({
66
+ environment,
67
+ children,
68
+ }: IsographEnvironmentProviderProps) {
69
+ const [, setState] = React.useState<object | void>();
70
+ React.useEffect(() => {
71
+ return subscribe(() => setState({}));
72
+ }, []);
73
+
74
+ return (
75
+ <IsographEnvironmentContext.Provider value={environment}>
76
+ {children}
77
+ </IsographEnvironmentContext.Provider>
78
+ );
79
+ }
80
+
81
+ export function useIsographEnvironment(): IsographEnvironment {
82
+ const context = useContext(IsographEnvironmentContext);
83
+ if (context == null) {
84
+ throw new Error(
85
+ 'Unexpected null environment context. Make sure to render ' +
86
+ 'this component within an IsographEnvironmentProvider component',
87
+ );
88
+ }
89
+ return context;
90
+ }
package/src/index.tsx CHANGED
@@ -1,27 +1,36 @@
1
1
  import {
2
- DataId,
3
- StoreRecord,
4
- DataTypeValue,
5
- Link,
6
- ROOT_ID,
7
2
  getOrCreateCacheForArtifact,
8
3
  onNextChange,
9
- getStore,
10
4
  getParentRecordKey,
11
5
  } from './cache';
12
6
  import { useLazyDisposableState } from '@isograph/react-disposable-state';
13
7
  import { type PromiseWrapper } from './PromiseWrapper';
14
8
  import { getOrCreateCachedComponent } from './componentCache';
15
-
16
- export {
17
- setNetwork,
18
- makeNetworkRequest,
19
- subscribe,
9
+ import {
20
10
  DataId,
11
+ DataTypeValue,
12
+ IsographEnvironment,
21
13
  Link,
14
+ ROOT_ID,
22
15
  StoreRecord,
23
- clearStore,
24
- } from './cache';
16
+ useIsographEnvironment,
17
+ } from './context';
18
+
19
+ export { makeNetworkRequest, subscribe } from './cache';
20
+ export {
21
+ IsographEnvironmentContext,
22
+ ROOT_ID,
23
+ type DataId,
24
+ type DataTypeValue,
25
+ type IsographEnvironment,
26
+ IsographEnvironmentProvider,
27
+ type IsographEnvironmentProviderProps,
28
+ type IsographNetworkFunction,
29
+ type IsographStore,
30
+ type Link,
31
+ type StoreRecord,
32
+ useIsographEnvironment,
33
+ } from './context';
25
34
 
26
35
  export { iso } from './iso';
27
36
 
@@ -177,7 +186,10 @@ function assertIsEntrypoint<
177
186
  >(
178
187
  value:
179
188
  | IsographEntrypoint<TReadFromStore, TResolverProps, TResolverResult>
180
- | typeof iso,
189
+ | ((_: any) => any)
190
+ // Temporarily, allow any here. Once we automatically provide
191
+ // types to entrypoints, we probably don't need this.
192
+ | any,
181
193
  ): asserts value is IsographEntrypoint<
182
194
  TReadFromStore,
183
195
  TResolverProps,
@@ -211,9 +223,11 @@ export function useLazyReference<TEntrypoint>(
211
223
  ExtractResolverResult<TEntrypoint>
212
224
  >;
213
225
  } {
226
+ const environment = useIsographEnvironment();
214
227
  assertIsEntrypoint(entrypoint);
215
228
  // Typechecking fails here... TODO investigate
216
229
  const cache = getOrCreateCacheForArtifact<ExtractResolverResult<TEntrypoint>>(
230
+ environment,
217
231
  entrypoint,
218
232
  variables,
219
233
  );
@@ -234,11 +248,27 @@ export function useLazyReference<TEntrypoint>(
234
248
  };
235
249
  }
236
250
 
251
+ export function useRead<
252
+ TReadFromStore extends Object,
253
+ TResolverProps,
254
+ TResolverResult,
255
+ >(
256
+ fragmentReference: FragmentReference<
257
+ TReadFromStore,
258
+ TResolverProps,
259
+ TResolverResult
260
+ >,
261
+ ): TResolverResult {
262
+ const environment = useIsographEnvironment();
263
+ return read(environment, fragmentReference);
264
+ }
265
+
237
266
  export function read<
238
267
  TReadFromStore extends Object,
239
268
  TResolverProps,
240
269
  TResolverResult,
241
270
  >(
271
+ environment: IsographEnvironment,
242
272
  fragmentReference: FragmentReference<
243
273
  TReadFromStore,
244
274
  TResolverProps,
@@ -248,6 +278,7 @@ export function read<
248
278
  const variant = fragmentReference.readerArtifact.variant;
249
279
  if (variant.kind === 'Eager') {
250
280
  const data = readData(
281
+ environment,
251
282
  fragmentReference.readerArtifact.readerAst,
252
283
  fragmentReference.root,
253
284
  fragmentReference.variables ?? {},
@@ -261,6 +292,7 @@ export function read<
261
292
  } else if (variant.kind === 'Component') {
262
293
  // @ts-ignore
263
294
  return getOrCreateCachedComponent(
295
+ environment,
264
296
  fragmentReference.root,
265
297
  variant.componentName,
266
298
  fragmentReference.readerArtifact,
@@ -273,9 +305,11 @@ export function read<
273
305
  }
274
306
 
275
307
  export function readButDoNotEvaluate<TReadFromStore extends Object>(
308
+ environment: IsographEnvironment,
276
309
  reference: FragmentReference<TReadFromStore, unknown, unknown>,
277
310
  ): TReadFromStore {
278
311
  const response = readData(
312
+ environment,
279
313
  reference.readerArtifact.readerAst,
280
314
  reference.root,
281
315
  reference.variables ?? {},
@@ -303,12 +337,13 @@ type ReadDataResult<TReadFromStore> =
303
337
  };
304
338
 
305
339
  function readData<TReadFromStore>(
340
+ environment: IsographEnvironment,
306
341
  ast: ReaderAst<TReadFromStore>,
307
342
  root: DataId,
308
343
  variables: { [index: string]: string },
309
344
  nestedRefetchQueries: RefetchQueryArtifactWrapper[],
310
345
  ): ReadDataResult<TReadFromStore> {
311
- let storeRecord = getStore()[root];
346
+ let storeRecord = environment.store[root];
312
347
  if (storeRecord === undefined) {
313
348
  return { kind: 'MissingData', reason: 'No record for root ' + root };
314
349
  }
@@ -358,6 +393,7 @@ function readData<TReadFromStore>(
358
393
  continue;
359
394
  }
360
395
  const result = readData(
396
+ environment,
361
397
  field.selections,
362
398
  link.__link,
363
399
  variables,
@@ -384,6 +420,8 @@ function readData<TReadFromStore>(
384
420
  let link = assertLink(value);
385
421
  if (link === undefined) {
386
422
  // TODO make this configurable, and also generated and derived from the schema
423
+ const missingFieldHandler =
424
+ environment.missingFieldHandler ?? defaultMissingFieldHandler;
387
425
  const altLink = missingFieldHandler(
388
426
  storeRecord,
389
427
  root,
@@ -411,6 +449,7 @@ function readData<TReadFromStore>(
411
449
  }
412
450
  const targetId = link.__link;
413
451
  const data = readData(
452
+ environment,
414
453
  field.selections,
415
454
  targetId,
416
455
  variables,
@@ -428,6 +467,7 @@ function readData<TReadFromStore>(
428
467
  }
429
468
  case 'RefetchField': {
430
469
  const data = readData(
470
+ environment,
431
471
  field.readerArtifact.readerAst,
432
472
  root,
433
473
  variables,
@@ -453,6 +493,7 @@ function readData<TReadFromStore>(
453
493
  const allowedVariables = refetchQuery.allowedVariables;
454
494
 
455
495
  target[field.alias] = field.readerArtifact.resolver(
496
+ environment,
456
497
  refetchQueryArtifact,
457
498
  {
458
499
  ...data.data,
@@ -466,6 +507,7 @@ function readData<TReadFromStore>(
466
507
  }
467
508
  case 'MutationField': {
468
509
  const data = readData(
510
+ environment,
469
511
  field.readerArtifact.readerAst,
470
512
  root,
471
513
  variables,
@@ -491,6 +533,7 @@ function readData<TReadFromStore>(
491
533
  const allowedVariables = refetchQuery.allowedVariables;
492
534
 
493
535
  target[field.alias] = field.readerArtifact.resolver(
536
+ environment,
494
537
  refetchQueryArtifact,
495
538
  data.data,
496
539
  filterVariables(variables, allowedVariables),
@@ -507,6 +550,7 @@ function readData<TReadFromStore>(
507
550
  const variant = field.readerArtifact.variant;
508
551
  if (variant.kind === 'Eager') {
509
552
  const data = readData(
553
+ environment,
510
554
  field.readerArtifact.readerAst,
511
555
  root,
512
556
  variables,
@@ -523,6 +567,7 @@ function readData<TReadFromStore>(
523
567
  }
524
568
  } else if (variant.kind === 'Component') {
525
569
  target[field.alias] = getOrCreateCachedComponent(
570
+ environment,
526
571
  root,
527
572
  variant.componentName,
528
573
  field.readerArtifact,
@@ -537,37 +582,9 @@ function readData<TReadFromStore>(
537
582
  return { kind: 'Success', data: target as any };
538
583
  }
539
584
 
540
- let customMissingFieldHandler: typeof defaultMissingFieldHandler | null = null;
541
-
542
- function missingFieldHandler(
543
- storeRecord: StoreRecord,
544
- root: DataId,
545
- fieldName: string,
546
- arguments_: { [index: string]: any } | null,
547
- variables: { [index: string]: any } | null,
548
- ): Link | undefined {
549
- if (customMissingFieldHandler != null) {
550
- return customMissingFieldHandler(
551
- storeRecord,
552
- root,
553
- fieldName,
554
- arguments_,
555
- variables,
556
- );
557
- } else {
558
- return defaultMissingFieldHandler(
559
- storeRecord,
560
- root,
561
- fieldName,
562
- arguments_,
563
- variables,
564
- );
565
- }
566
- }
567
-
568
585
  export function defaultMissingFieldHandler(
569
- storeRecord: StoreRecord,
570
- root: DataId,
586
+ _storeRecord: StoreRecord,
587
+ _root: DataId,
571
588
  fieldName: string,
572
589
  arguments_: { [index: string]: any } | null,
573
590
  variables: { [index: string]: any } | null,
@@ -583,12 +600,6 @@ export function defaultMissingFieldHandler(
583
600
  }
584
601
  }
585
602
 
586
- export function setMissingFieldHandler(
587
- handler: typeof defaultMissingFieldHandler,
588
- ) {
589
- customMissingFieldHandler = handler;
590
- }
591
-
592
603
  function assertLink(link: DataTypeValue): Link | undefined | null {
593
604
  if (Array.isArray(link)) {
594
605
  throw new Error('Unexpected array');