@isograph/react 0.4.3 → 0.5.1

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 (327) hide show
  1. package/.turbo/turbo-compile-libs.log +10 -3
  2. package/dist/_virtual/rolldown_runtime.js +25 -0
  3. package/dist/core/FragmentReference.d.mts +38 -0
  4. package/dist/core/FragmentReference.d.mts.map +1 -0
  5. package/dist/core/FragmentReference.d.ts +31 -27
  6. package/dist/core/FragmentReference.d.ts.map +1 -1
  7. package/dist/core/FragmentReference.js +8 -6
  8. package/dist/core/FragmentReference.mjs +10 -0
  9. package/dist/core/FragmentReference.mjs.map +1 -0
  10. package/dist/core/IsographEnvironment.d.mts +89 -0
  11. package/dist/core/IsographEnvironment.d.mts.map +1 -0
  12. package/dist/core/IsographEnvironment.d.ts +77 -72
  13. package/dist/core/IsographEnvironment.d.ts.map +1 -1
  14. package/dist/core/IsographEnvironment.js +62 -59
  15. package/dist/core/IsographEnvironment.mjs +67 -0
  16. package/dist/core/IsographEnvironment.mjs.map +1 -0
  17. package/dist/core/PromiseWrapper.d.mts +36 -0
  18. package/dist/core/PromiseWrapper.d.mts.map +1 -0
  19. package/dist/core/PromiseWrapper.d.ts +27 -18
  20. package/dist/core/PromiseWrapper.d.ts.map +1 -1
  21. package/dist/core/PromiseWrapper.js +45 -43
  22. package/dist/core/PromiseWrapper.mjs +49 -0
  23. package/dist/core/PromiseWrapper.mjs.map +1 -0
  24. package/dist/core/areEqualWithDeepComparison.js +56 -108
  25. package/dist/core/areEqualWithDeepComparison.mjs +62 -0
  26. package/dist/core/areEqualWithDeepComparison.mjs.map +1 -0
  27. package/dist/core/brand.d.mts +19 -0
  28. package/dist/core/brand.d.mts.map +1 -0
  29. package/dist/core/brand.d.ts +18 -1
  30. package/dist/core/brand.d.ts.map +1 -1
  31. package/dist/core/cache.d.mts +20 -0
  32. package/dist/core/cache.d.mts.map +1 -0
  33. package/dist/core/cache.d.ts +18 -34
  34. package/dist/core/cache.d.ts.map +1 -1
  35. package/dist/core/cache.js +210 -516
  36. package/dist/core/cache.mjs +237 -0
  37. package/dist/core/cache.mjs.map +1 -0
  38. package/dist/core/check.d.mts +28 -0
  39. package/dist/core/check.d.mts.map +1 -0
  40. package/dist/core/check.d.ts +24 -18
  41. package/dist/core/check.d.ts.map +1 -1
  42. package/dist/core/check.js +80 -124
  43. package/dist/core/check.mjs +84 -0
  44. package/dist/core/check.mjs.map +1 -0
  45. package/dist/core/componentCache.js +10 -34
  46. package/dist/core/componentCache.mjs +12 -0
  47. package/dist/core/componentCache.mjs.map +1 -0
  48. package/dist/core/entrypoint.d.mts +99 -0
  49. package/dist/core/entrypoint.d.mts.map +1 -0
  50. package/dist/core/entrypoint.d.ts +83 -68
  51. package/dist/core/entrypoint.d.ts.map +1 -1
  52. package/dist/core/entrypoint.js +6 -5
  53. package/dist/core/entrypoint.mjs +8 -0
  54. package/dist/core/entrypoint.mjs.map +1 -0
  55. package/dist/core/garbageCollection.d.mts +18 -0
  56. package/dist/core/garbageCollection.d.mts.map +1 -0
  57. package/dist/core/garbageCollection.d.ts +15 -10
  58. package/dist/core/garbageCollection.d.ts.map +1 -1
  59. package/dist/core/garbageCollection.js +82 -99
  60. package/dist/core/garbageCollection.mjs +89 -0
  61. package/dist/core/garbageCollection.mjs.map +1 -0
  62. package/dist/core/getOrCreateCacheForArtifact.js +37 -0
  63. package/dist/core/getOrCreateCacheForArtifact.mjs +38 -0
  64. package/dist/core/getOrCreateCacheForArtifact.mjs.map +1 -0
  65. package/dist/core/logging.d.mts +95 -0
  66. package/dist/core/logging.d.mts.map +1 -0
  67. package/dist/core/logging.d.ts +78 -60
  68. package/dist/core/logging.d.ts.map +1 -1
  69. package/dist/core/logging.js +17 -18
  70. package/dist/core/logging.mjs +20 -0
  71. package/dist/core/logging.mjs.map +1 -0
  72. package/dist/core/makeNetworkRequest.d.mts +13 -0
  73. package/dist/core/makeNetworkRequest.d.mts.map +1 -0
  74. package/dist/core/makeNetworkRequest.d.ts +12 -8
  75. package/dist/core/makeNetworkRequest.d.ts.map +1 -1
  76. package/dist/core/makeNetworkRequest.js +188 -195
  77. package/dist/core/makeNetworkRequest.mjs +195 -0
  78. package/dist/core/makeNetworkRequest.mjs.map +1 -0
  79. package/dist/core/optimisticProxy.d.mts +43 -0
  80. package/dist/core/optimisticProxy.d.mts.map +1 -0
  81. package/dist/core/optimisticProxy.d.ts +43 -0
  82. package/dist/core/optimisticProxy.d.ts.map +1 -0
  83. package/dist/core/optimisticProxy.js +273 -0
  84. package/dist/core/optimisticProxy.mjs +268 -0
  85. package/dist/core/optimisticProxy.mjs.map +1 -0
  86. package/dist/core/read.d.mts +29 -0
  87. package/dist/core/read.d.mts.map +1 -0
  88. package/dist/core/read.d.ts +23 -27
  89. package/dist/core/read.d.ts.map +1 -1
  90. package/dist/core/read.js +438 -618
  91. package/dist/core/read.mjs +456 -0
  92. package/dist/core/read.mjs.map +1 -0
  93. package/dist/core/reader.d.mts +89 -0
  94. package/dist/core/reader.d.mts.map +1 -0
  95. package/dist/core/reader.d.ts +78 -74
  96. package/dist/core/reader.d.ts.map +1 -1
  97. package/dist/core/startUpdate.js +118 -156
  98. package/dist/core/startUpdate.mjs +125 -0
  99. package/dist/core/startUpdate.mjs.map +1 -0
  100. package/dist/core/subscribe.d.mts +12 -0
  101. package/dist/core/subscribe.d.mts.map +1 -0
  102. package/dist/core/subscribe.d.ts +12 -0
  103. package/dist/core/subscribe.d.ts.map +1 -0
  104. package/dist/core/subscribe.js +79 -0
  105. package/dist/core/subscribe.mjs +79 -0
  106. package/dist/core/subscribe.mjs.map +1 -0
  107. package/dist/core/util.d.mts +27 -0
  108. package/dist/core/util.d.mts.map +1 -0
  109. package/dist/core/util.d.ts +21 -17
  110. package/dist/core/util.d.ts.map +1 -1
  111. package/dist/core/util.js +22 -2
  112. package/dist/core/util.mjs +21 -0
  113. package/dist/core/util.mjs.map +1 -0
  114. package/dist/core/writeData.d.mts +11 -0
  115. package/dist/core/writeData.d.mts.map +1 -0
  116. package/dist/core/writeData.d.ts +11 -0
  117. package/dist/core/writeData.d.ts.map +1 -0
  118. package/dist/core/writeData.js +41 -0
  119. package/dist/core/writeData.mjs +42 -0
  120. package/dist/core/writeData.mjs.map +1 -0
  121. package/dist/index.d.mts +32 -0
  122. package/dist/index.d.ts +32 -29
  123. package/dist/index.js +70 -68
  124. package/dist/index.mjs +31 -0
  125. package/dist/loadable-hooks/useClientSideDefer.d.mts +12 -0
  126. package/dist/loadable-hooks/useClientSideDefer.d.mts.map +1 -0
  127. package/dist/loadable-hooks/useClientSideDefer.d.ts +10 -8
  128. package/dist/loadable-hooks/useClientSideDefer.d.ts.map +1 -1
  129. package/dist/loadable-hooks/useClientSideDefer.js +14 -12
  130. package/dist/loadable-hooks/useClientSideDefer.mjs +14 -0
  131. package/dist/loadable-hooks/useClientSideDefer.mjs.map +1 -0
  132. package/dist/loadable-hooks/useConnectionSpecPagination.d.mts +33 -0
  133. package/dist/loadable-hooks/useConnectionSpecPagination.d.mts.map +1 -0
  134. package/dist/loadable-hooks/useConnectionSpecPagination.d.ts +27 -21
  135. package/dist/loadable-hooks/useConnectionSpecPagination.d.ts.map +1 -1
  136. package/dist/loadable-hooks/useConnectionSpecPagination.js +133 -158
  137. package/dist/loadable-hooks/useConnectionSpecPagination.mjs +134 -0
  138. package/dist/loadable-hooks/useConnectionSpecPagination.mjs.map +1 -0
  139. package/dist/loadable-hooks/useImperativeExposedMutationField.d.mts +8 -0
  140. package/dist/loadable-hooks/useImperativeExposedMutationField.d.mts.map +1 -0
  141. package/dist/loadable-hooks/useImperativeExposedMutationField.d.ts +6 -3
  142. package/dist/loadable-hooks/useImperativeExposedMutationField.d.ts.map +1 -1
  143. package/dist/loadable-hooks/useImperativeExposedMutationField.js +9 -12
  144. package/dist/loadable-hooks/useImperativeExposedMutationField.mjs +11 -0
  145. package/dist/loadable-hooks/useImperativeExposedMutationField.mjs.map +1 -0
  146. package/dist/loadable-hooks/useImperativeLoadableField.d.mts +19 -0
  147. package/dist/loadable-hooks/useImperativeLoadableField.d.mts.map +1 -0
  148. package/dist/loadable-hooks/useImperativeLoadableField.d.ts +15 -11
  149. package/dist/loadable-hooks/useImperativeLoadableField.d.ts.map +1 -1
  150. package/dist/loadable-hooks/useImperativeLoadableField.js +16 -12
  151. package/dist/loadable-hooks/useImperativeLoadableField.mjs +17 -0
  152. package/dist/loadable-hooks/useImperativeLoadableField.mjs.map +1 -0
  153. package/dist/loadable-hooks/useSkipLimitPagination.d.mts +24 -0
  154. package/dist/loadable-hooks/useSkipLimitPagination.d.mts.map +1 -0
  155. package/dist/loadable-hooks/useSkipLimitPagination.d.ts +19 -15
  156. package/dist/loadable-hooks/useSkipLimitPagination.d.ts.map +1 -1
  157. package/dist/loadable-hooks/useSkipLimitPagination.js +118 -160
  158. package/dist/loadable-hooks/useSkipLimitPagination.mjs +119 -0
  159. package/dist/loadable-hooks/useSkipLimitPagination.mjs.map +1 -0
  160. package/dist/react/FragmentReader.d.mts +18 -0
  161. package/dist/react/FragmentReader.d.mts.map +1 -0
  162. package/dist/react/FragmentReader.d.ts +16 -7
  163. package/dist/react/FragmentReader.d.ts.map +1 -1
  164. package/dist/react/FragmentReader.js +8 -7
  165. package/dist/react/FragmentReader.mjs +10 -0
  166. package/dist/react/FragmentReader.mjs.map +1 -0
  167. package/dist/react/FragmentRenderer.d.mts +20 -0
  168. package/dist/react/FragmentRenderer.d.mts.map +1 -0
  169. package/dist/react/FragmentRenderer.d.ts +18 -13
  170. package/dist/react/FragmentRenderer.d.ts.map +1 -1
  171. package/dist/react/FragmentRenderer.js +11 -33
  172. package/dist/react/FragmentRenderer.mjs +12 -0
  173. package/dist/react/FragmentRenderer.mjs.map +1 -0
  174. package/dist/react/IsographEnvironmentProvider.d.mts +17 -0
  175. package/dist/react/IsographEnvironmentProvider.d.mts.map +1 -0
  176. package/dist/react/IsographEnvironmentProvider.d.ts +15 -9
  177. package/dist/react/IsographEnvironmentProvider.d.ts.map +1 -1
  178. package/dist/react/IsographEnvironmentProvider.js +15 -39
  179. package/dist/react/IsographEnvironmentProvider.mjs +17 -0
  180. package/dist/react/IsographEnvironmentProvider.mjs.map +1 -0
  181. package/dist/react/LoadableFieldReader.d.mts +21 -0
  182. package/dist/react/LoadableFieldReader.d.mts.map +1 -0
  183. package/dist/react/LoadableFieldReader.d.ts +20 -11
  184. package/dist/react/LoadableFieldReader.d.ts.map +1 -1
  185. package/dist/react/LoadableFieldReader.js +13 -8
  186. package/dist/react/LoadableFieldReader.mjs +14 -0
  187. package/dist/react/LoadableFieldReader.mjs.map +1 -0
  188. package/dist/react/LoadableFieldRenderer.d.mts +22 -0
  189. package/dist/react/LoadableFieldRenderer.d.mts.map +1 -0
  190. package/dist/react/LoadableFieldRenderer.d.ts +21 -12
  191. package/dist/react/LoadableFieldRenderer.d.ts.map +1 -1
  192. package/dist/react/LoadableFieldRenderer.js +13 -35
  193. package/dist/react/LoadableFieldRenderer.mjs +14 -0
  194. package/dist/react/LoadableFieldRenderer.mjs.map +1 -0
  195. package/dist/react/RenderAfterCommit__DO_NOT_USE.d.mts +18 -0
  196. package/dist/react/RenderAfterCommit__DO_NOT_USE.d.mts.map +1 -0
  197. package/dist/react/RenderAfterCommit__DO_NOT_USE.d.ts +11 -3
  198. package/dist/react/RenderAfterCommit__DO_NOT_USE.d.ts.map +1 -1
  199. package/dist/react/RenderAfterCommit__DO_NOT_USE.js +17 -13
  200. package/dist/react/RenderAfterCommit__DO_NOT_USE.mjs +18 -0
  201. package/dist/react/RenderAfterCommit__DO_NOT_USE.mjs.map +1 -0
  202. package/dist/react/createIsographEnvironment.d.mts +9 -0
  203. package/dist/react/createIsographEnvironment.d.mts.map +1 -0
  204. package/dist/react/createIsographEnvironment.d.ts +8 -0
  205. package/dist/react/createIsographEnvironment.d.ts.map +1 -0
  206. package/dist/react/createIsographEnvironment.js +10 -0
  207. package/dist/react/createIsographEnvironment.mjs +11 -0
  208. package/dist/react/createIsographEnvironment.mjs.map +1 -0
  209. package/dist/react/maybeUnwrapNetworkRequest.js +11 -0
  210. package/dist/react/maybeUnwrapNetworkRequest.mjs +12 -0
  211. package/dist/react/maybeUnwrapNetworkRequest.mjs.map +1 -0
  212. package/dist/react/useImperativeReference.d.mts +15 -0
  213. package/dist/react/useImperativeReference.d.mts.map +1 -0
  214. package/dist/react/useImperativeReference.d.ts +13 -7
  215. package/dist/react/useImperativeReference.d.ts.map +1 -1
  216. package/dist/react/useImperativeReference.js +34 -32
  217. package/dist/react/useImperativeReference.mjs +35 -0
  218. package/dist/react/useImperativeReference.mjs.map +1 -0
  219. package/dist/react/useLazyReference.d.mts +13 -0
  220. package/dist/react/useLazyReference.d.mts.map +1 -0
  221. package/dist/react/useLazyReference.d.ts +11 -5
  222. package/dist/react/useLazyReference.d.ts.map +1 -1
  223. package/dist/react/useLazyReference.js +17 -40
  224. package/dist/react/useLazyReference.mjs +18 -0
  225. package/dist/react/useLazyReference.mjs.map +1 -0
  226. package/dist/react/useReadAndSubscribe.d.mts +20 -0
  227. package/dist/react/useReadAndSubscribe.d.mts.map +1 -0
  228. package/dist/react/useReadAndSubscribe.d.ts +14 -9
  229. package/dist/react/useReadAndSubscribe.d.ts.map +1 -1
  230. package/dist/react/useReadAndSubscribe.js +57 -39
  231. package/dist/react/useReadAndSubscribe.mjs +59 -0
  232. package/dist/react/useReadAndSubscribe.mjs.map +1 -0
  233. package/dist/react/useRerenderOnChange.d.mts +12 -0
  234. package/dist/react/useRerenderOnChange.d.mts.map +1 -0
  235. package/dist/react/useRerenderOnChange.d.ts +10 -6
  236. package/dist/react/useRerenderOnChange.d.ts.map +1 -1
  237. package/dist/react/useRerenderOnChange.js +16 -20
  238. package/dist/react/useRerenderOnChange.mjs +17 -0
  239. package/dist/react/useRerenderOnChange.mjs.map +1 -0
  240. package/dist/react/useResult.d.mts +8 -0
  241. package/dist/react/useResult.d.mts.map +1 -0
  242. package/dist/react/useResult.d.ts +7 -5
  243. package/dist/react/useResult.d.ts.map +1 -1
  244. package/dist/react/useResult.js +27 -39
  245. package/dist/react/useResult.mjs +30 -0
  246. package/dist/react/useResult.mjs.map +1 -0
  247. package/package.json +26 -19
  248. package/src/core/FragmentReference.ts +13 -7
  249. package/src/core/IsographEnvironment.ts +80 -21
  250. package/src/core/PromiseWrapper.ts +14 -7
  251. package/src/core/areEqualWithDeepComparison.ts +2 -18
  252. package/src/core/brand.ts +18 -0
  253. package/src/core/cache.ts +62 -332
  254. package/src/core/check.ts +30 -26
  255. package/src/core/componentCache.ts +11 -44
  256. package/src/core/entrypoint.ts +50 -9
  257. package/src/core/garbageCollection.ts +81 -28
  258. package/src/core/getOrCreateCacheForArtifact.ts +86 -0
  259. package/src/core/logging.ts +25 -13
  260. package/src/core/makeNetworkRequest.ts +320 -94
  261. package/src/core/optimisticProxy.ts +544 -0
  262. package/src/core/read.ts +251 -198
  263. package/src/core/reader.ts +18 -17
  264. package/src/core/startUpdate.ts +47 -36
  265. package/src/core/subscribe.ts +189 -0
  266. package/src/core/util.ts +26 -0
  267. package/src/core/writeData.ts +79 -0
  268. package/src/index.ts +6 -4
  269. package/src/loadable-hooks/useClientSideDefer.ts +80 -30
  270. package/src/loadable-hooks/useConnectionSpecPagination.ts +54 -35
  271. package/src/loadable-hooks/useImperativeLoadableField.ts +5 -5
  272. package/src/loadable-hooks/useSkipLimitPagination.ts +22 -21
  273. package/src/react/FragmentReader.tsx +3 -1
  274. package/src/react/FragmentRenderer.tsx +8 -1
  275. package/src/react/IsographEnvironmentProvider.tsx +2 -1
  276. package/src/react/LoadableFieldReader.tsx +125 -16
  277. package/src/react/LoadableFieldRenderer.tsx +124 -16
  278. package/src/react/createIsographEnvironment.ts +23 -0
  279. package/src/react/maybeUnwrapNetworkRequest.ts +17 -0
  280. package/src/react/useImperativeReference.ts +25 -15
  281. package/src/react/useLazyReference.ts +20 -10
  282. package/src/react/useReadAndSubscribe.ts +53 -12
  283. package/src/react/useRerenderOnChange.ts +3 -3
  284. package/src/react/useResult.ts +15 -35
  285. package/src/tests/__isograph/Node/asEconomist/resolver_reader.ts +1 -1
  286. package/src/tests/__isograph/Query/linkedUpdate/entrypoint.ts +3 -1
  287. package/src/tests/__isograph/Query/linkedUpdate/raw_response_type.ts +13 -0
  288. package/src/tests/__isograph/Query/linkedUpdate/resolver_reader.ts +1 -1
  289. package/src/tests/__isograph/Query/meName/entrypoint.ts +3 -1
  290. package/src/tests/__isograph/Query/meName/raw_response_type.ts +7 -0
  291. package/src/tests/__isograph/Query/meName/resolver_reader.ts +1 -1
  292. package/src/tests/__isograph/Query/meNameSuccessor/entrypoint.ts +3 -1
  293. package/src/tests/__isograph/Query/meNameSuccessor/raw_response_type.ts +14 -0
  294. package/src/tests/__isograph/Query/meNameSuccessor/resolver_reader.ts +1 -1
  295. package/src/tests/__isograph/Query/nodeField/entrypoint.ts +3 -1
  296. package/src/tests/__isograph/Query/nodeField/raw_response_type.ts +7 -0
  297. package/src/tests/__isograph/Query/nodeField/resolver_reader.ts +1 -1
  298. package/src/tests/__isograph/Query/normalizeUndefinedField/entrypoint.ts +33 -0
  299. package/src/tests/__isograph/Query/normalizeUndefinedField/normalization_ast.ts +25 -0
  300. package/src/tests/__isograph/Query/normalizeUndefinedField/output_type.ts +3 -0
  301. package/src/tests/__isograph/Query/normalizeUndefinedField/param_type.ts +9 -0
  302. package/src/tests/__isograph/Query/normalizeUndefinedField/query_text.ts +6 -0
  303. package/src/tests/__isograph/Query/normalizeUndefinedField/raw_response_type.ts +7 -0
  304. package/src/tests/__isograph/Query/normalizeUndefinedField/resolver_reader.ts +38 -0
  305. package/src/tests/__isograph/Query/startUpdate/entrypoint.ts +3 -1
  306. package/src/tests/__isograph/Query/startUpdate/raw_response_type.ts +8 -0
  307. package/src/tests/__isograph/Query/startUpdate/resolver_reader.ts +1 -1
  308. package/src/tests/__isograph/Query/subquery/entrypoint.ts +3 -1
  309. package/src/tests/__isograph/Query/subquery/raw_response_type.ts +9 -0
  310. package/src/tests/__isograph/Query/subquery/resolver_reader.ts +1 -1
  311. package/src/tests/__isograph/iso.ts +11 -1
  312. package/src/tests/garbageCollection.test.ts +10 -10
  313. package/src/tests/meNameSuccessor.ts +7 -4
  314. package/src/tests/nodeQuery.ts +6 -4
  315. package/src/tests/normalizeData.test.ts +94 -18
  316. package/src/tests/optimisticProxy.test.ts +862 -0
  317. package/src/tests/startUpdate.test.ts +11 -11
  318. package/vitest.config.ts +5 -0
  319. package/dist/core/areEqualWithDeepComparison.d.ts +0 -3
  320. package/dist/core/areEqualWithDeepComparison.d.ts.map +0 -1
  321. package/dist/core/brand.js +0 -2
  322. package/dist/core/componentCache.d.ts +0 -5
  323. package/dist/core/componentCache.d.ts.map +0 -1
  324. package/dist/core/reader.js +0 -2
  325. package/dist/core/startUpdate.d.ts +0 -8
  326. package/dist/core/startUpdate.d.ts.map +0 -1
  327. package/dist/index.d.ts.map +0 -1
@@ -1,5 +1,4 @@
1
1
  import {
2
- callSubscriptions,
3
2
  getParentRecordKey,
4
3
  insertEmptySetIfMissing,
5
4
  type EncounteredIds,
@@ -19,6 +18,13 @@ import {
19
18
  type StoreLink,
20
19
  } from './IsographEnvironment';
21
20
  import { logMessage } from './logging';
21
+ import {
22
+ addStartUpdateStoreLayer,
23
+ getMutableStoreRecordProxy,
24
+ getOrInsertRecord,
25
+ type StartUpdateStoreLayer,
26
+ type StoreLayer,
27
+ } from './optimisticProxy';
22
28
  import { readPromise, type PromiseWrapper } from './PromiseWrapper';
23
29
  import {
24
30
  readImperativelyLoadedField,
@@ -30,17 +36,17 @@ import {
30
36
  type ReadDataResultSuccess,
31
37
  } from './read';
32
38
  import type { ReaderAst } from './reader';
39
+ import { callSubscriptions } from './subscribe';
33
40
 
34
41
  export function getOrCreateCachedStartUpdate<
35
42
  TReadFromStore extends UnknownTReadFromStore,
36
43
  >(
37
44
  environment: IsographEnvironment,
38
45
  fragmentReference: FragmentReference<TReadFromStore, unknown>,
39
- eagerResolverName: string,
40
46
  networkRequestOptions: NetworkRequestReaderOptions,
41
47
  ): ExtractStartUpdate<TReadFromStore> {
42
48
  return (environment.eagerReaderCache[
43
- stableIdForFragmentReference(fragmentReference, eagerResolverName)
49
+ stableIdForFragmentReference(fragmentReference)
44
50
  ] ??= createStartUpdate(
45
51
  environment,
46
52
  fragmentReference,
@@ -56,28 +62,38 @@ export function createStartUpdate<TReadFromStore extends UnknownTReadFromStore>(
56
62
  return (updater) => {
57
63
  let mutableUpdatedIds: EncounteredIds = new Map();
58
64
 
59
- let updatableData = createUpdatableProxy(
60
- environment,
61
- fragmentReference,
62
- networkRequestOptions,
63
- mutableUpdatedIds,
65
+ const startUpdate: StartUpdateStoreLayer['startUpdate'] = (storeLayer) => {
66
+ mutableUpdatedIds.clear();
67
+ let updatableData = createUpdatableProxy(
68
+ environment,
69
+ storeLayer,
70
+ fragmentReference,
71
+ networkRequestOptions,
72
+ mutableUpdatedIds,
73
+ );
74
+
75
+ try {
76
+ updater({ updatableData });
77
+ } catch (e) {
78
+ logMessage(environment, () => ({
79
+ kind: 'StartUpdateError',
80
+ error: e,
81
+ }));
82
+ throw e;
83
+ }
84
+ };
85
+
86
+ environment.store = addStartUpdateStoreLayer(
87
+ environment.store,
88
+ startUpdate,
64
89
  );
65
90
 
66
- try {
67
- updater({ updatableData });
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
- }
91
+ logMessage(environment, () => ({
92
+ kind: 'StartUpdateComplete',
93
+ updatedIds: mutableUpdatedIds,
94
+ }));
95
+
96
+ callSubscriptions(environment, mutableUpdatedIds);
81
97
  };
82
98
  }
83
99
 
@@ -85,6 +101,7 @@ export function createUpdatableProxy<
85
101
  TReadFromStore extends UnknownTReadFromStore,
86
102
  >(
87
103
  environment: IsographEnvironment,
104
+ storeLayer: StoreLayer,
88
105
  fragmentReference: FragmentReference<TReadFromStore, unknown>,
89
106
  networkRequestOptions: NetworkRequestReaderOptions,
90
107
  mutableUpdatedIds: EncounteredIds,
@@ -95,6 +112,7 @@ export function createUpdatableProxy<
95
112
 
96
113
  return readUpdatableData(
97
114
  environment,
115
+ storeLayer,
98
116
  readerWithRefetchQueries.readerArtifact.readerAst,
99
117
  fragmentReference.root,
100
118
  fragmentReference.variables ?? {},
@@ -143,7 +161,7 @@ function defineCachedProperty<T>(
143
161
  }
144
162
  return value.value;
145
163
  },
146
- ...(set && {
164
+ ...(set != null && {
147
165
  set: (newValue) => {
148
166
  set(newValue);
149
167
  mutableState.lastInvalidated++;
@@ -154,6 +172,7 @@ function defineCachedProperty<T>(
154
172
 
155
173
  function readUpdatableData<TReadFromStore extends UnknownTReadFromStore>(
156
174
  environment: IsographEnvironment,
175
+ storeLayer: StoreLayer,
157
176
  ast: ReaderAst<TReadFromStore>,
158
177
  root: StoreLink,
159
178
  variables: ExtractParameters<TReadFromStore>,
@@ -163,14 +182,7 @@ function readUpdatableData<TReadFromStore extends UnknownTReadFromStore>(
163
182
  mutableState: MutableInvalidationState,
164
183
  mutableUpdatedIds: EncounteredIds,
165
184
  ): 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
-
185
+ const storeRecord = getMutableStoreRecordProxy(storeLayer, root);
174
186
  let target: { [index: string]: any } = {};
175
187
 
176
188
  for (const field of ast) {
@@ -196,6 +208,7 @@ function readUpdatableData<TReadFromStore extends UnknownTReadFromStore>(
196
208
  },
197
209
  field.isUpdatable
198
210
  ? (newValue) => {
211
+ const storeRecord = getOrInsertRecord(storeLayer.data, root);
199
212
  storeRecord[storeRecordName] = newValue;
200
213
  const updatedIds = insertEmptySetIfMissing(
201
214
  mutableUpdatedIds,
@@ -226,6 +239,7 @@ function readUpdatableData<TReadFromStore extends UnknownTReadFromStore>(
226
239
  (ast, root) =>
227
240
  readUpdatableData(
228
241
  environment,
242
+ storeLayer,
229
243
  ast,
230
244
  root,
231
245
  variables,
@@ -243,6 +257,7 @@ function readUpdatableData<TReadFromStore extends UnknownTReadFromStore>(
243
257
  },
244
258
  'isUpdatable' in field && field.isUpdatable
245
259
  ? (newValue) => {
260
+ const storeRecord = getOrInsertRecord(storeLayer.data, root);
246
261
  if (Array.isArray(newValue)) {
247
262
  storeRecord[storeRecordName] = newValue.map((node) =>
248
263
  assertLink(node?.__link),
@@ -320,10 +335,6 @@ function readUpdatableData<TReadFromStore extends UnknownTReadFromStore>(
320
335
  target[field.alias] = root;
321
336
  break;
322
337
  }
323
- default: {
324
- field satisfies never;
325
- throw new Error('Unexpected case.');
326
- }
327
338
  }
328
339
  }
329
340
 
@@ -0,0 +1,189 @@
1
+ import { mergeObjectsUsingReaderAst } from './areEqualWithDeepComparison';
2
+ import type { EncounteredIds } from './cache';
3
+ import type {
4
+ FragmentReference,
5
+ UnknownTReadFromStore,
6
+ } from './FragmentReference';
7
+ import type {
8
+ FragmentSubscription,
9
+ IsographEnvironment,
10
+ } from './IsographEnvironment';
11
+ import { logMessage } from './logging';
12
+ import { type WithEncounteredRecords, readButDoNotEvaluate } from './read';
13
+ import type { ReaderAst } from './reader';
14
+
15
+ export function subscribe<TReadFromStore extends UnknownTReadFromStore>(
16
+ environment: IsographEnvironment,
17
+ encounteredDataAndRecords: WithEncounteredRecords<TReadFromStore>,
18
+ fragmentReference: FragmentReference<TReadFromStore, any>,
19
+ callback: (
20
+ newEncounteredDataAndRecords: WithEncounteredRecords<TReadFromStore>,
21
+ ) => void,
22
+ readerAst: ReaderAst<TReadFromStore>,
23
+ ): () => void {
24
+ const fragmentSubscription: FragmentSubscription<TReadFromStore> = {
25
+ kind: 'FragmentSubscription',
26
+ callback,
27
+ encounteredDataAndRecords,
28
+ fragmentReference,
29
+ readerAst,
30
+ };
31
+
32
+ // subscribe is called in an effect. (We should actually subscribe during the
33
+ // initial render.) Because it's called in an effect, we might have missed some
34
+ // changes since the initial render! So, at this point, we re-read and call the
35
+ // subscription (i.e. re-render) if the fragment data has changed.
36
+ callSubscriptionIfDataChanged(environment, fragmentSubscription);
37
+
38
+ environment.subscriptions.add(fragmentSubscription);
39
+ return () => environment.subscriptions.delete(fragmentSubscription);
40
+ }
41
+
42
+ // Calls to readButDoNotEvaluate can suspend (i.e. throw a promise).
43
+ // Maybe in the future, they will be able to throw errors.
44
+ //
45
+ // That's probably okay to ignore. We don't, however, want to prevent
46
+ // updating other subscriptions if one subscription had missing data.
47
+ function logAnyError(
48
+ environment: IsographEnvironment,
49
+ context: any,
50
+ f: () => void,
51
+ ) {
52
+ try {
53
+ f();
54
+ } catch (e) {
55
+ logMessage(environment, () => ({
56
+ kind: 'ErrorEncounteredInWithErrorHandling',
57
+ error: e,
58
+ context,
59
+ }));
60
+ }
61
+ }
62
+
63
+ export function callSubscriptions(
64
+ environment: IsographEnvironment,
65
+ recordsEncounteredWhenNormalizing: EncounteredIds,
66
+ ) {
67
+ environment.subscriptions.forEach((subscription) =>
68
+ logAnyError(environment, { situation: 'calling subscriptions' }, () => {
69
+ switch (subscription.kind) {
70
+ case 'FragmentSubscription': {
71
+ // TODO if there are multiple components subscribed to the same
72
+ // fragment, we will call readButNotEvaluate multiple times. We
73
+ // should fix that.
74
+ if (
75
+ hasOverlappingIds(
76
+ recordsEncounteredWhenNormalizing,
77
+ subscription.encounteredDataAndRecords.encounteredRecords,
78
+ )
79
+ ) {
80
+ callSubscriptionIfDataChanged(environment, subscription);
81
+ }
82
+ return;
83
+ }
84
+ case 'AnyRecords': {
85
+ logAnyError(
86
+ environment,
87
+ { situation: 'calling AnyRecords callback' },
88
+ () => subscription.callback(),
89
+ );
90
+ return;
91
+ }
92
+ case 'AnyChangesToRecord': {
93
+ if (
94
+ recordsEncounteredWhenNormalizing
95
+ .get(subscription.recordLink.__typename)
96
+ ?.has(subscription.recordLink.__link) != null
97
+ ) {
98
+ logAnyError(
99
+ environment,
100
+ { situation: 'calling AnyChangesToRecord callback' },
101
+ () => subscription.callback(),
102
+ );
103
+ }
104
+ return;
105
+ }
106
+ }
107
+ }),
108
+ );
109
+ }
110
+
111
+ function callSubscriptionIfDataChanged<
112
+ TReadFromStore extends UnknownTReadFromStore,
113
+ >(
114
+ environment: IsographEnvironment,
115
+ subscription: FragmentSubscription<TReadFromStore>,
116
+ ) {
117
+ const newEncounteredDataAndRecords = readButDoNotEvaluate(
118
+ environment,
119
+ subscription.fragmentReference,
120
+ // Is this wrong?
121
+ // Reasons to think no:
122
+ // - we are only updating the read-out value, and the network
123
+ // options only affect whether we throw.
124
+ // - the component will re-render, and re-throw on its own, anyway.
125
+ //
126
+ // Reasons to think not:
127
+ // - it seems more efficient to suspend here and not update state,
128
+ // if we expect that the component will just throw anyway
129
+ // - consistency
130
+ // - it's also weird, this is called from makeNetworkRequest, where
131
+ // we don't currently pass network request options
132
+ {
133
+ suspendIfInFlight: false,
134
+ throwOnNetworkError: false,
135
+ },
136
+ );
137
+
138
+ const mergedItem = mergeObjectsUsingReaderAst(
139
+ subscription.readerAst,
140
+ subscription.encounteredDataAndRecords.item,
141
+ newEncounteredDataAndRecords.item,
142
+ );
143
+
144
+ logMessage(environment, () => ({
145
+ kind: 'DeepEqualityCheck',
146
+ fragmentReference: subscription.fragmentReference,
147
+ old: subscription.encounteredDataAndRecords.item,
148
+ new: newEncounteredDataAndRecords.item,
149
+ deeplyEqual: mergedItem === subscription.encounteredDataAndRecords.item,
150
+ }));
151
+
152
+ if (mergedItem !== subscription.encounteredDataAndRecords.item) {
153
+ logAnyError(
154
+ environment,
155
+ { situation: 'calling FragmentSubscription callback' },
156
+ () => {
157
+ subscription.callback(newEncounteredDataAndRecords);
158
+ },
159
+ );
160
+ subscription.encounteredDataAndRecords = newEncounteredDataAndRecords;
161
+ }
162
+ }
163
+
164
+ function hasOverlappingIds(
165
+ ids1: EncounteredIds,
166
+ ids2: EncounteredIds,
167
+ ): boolean {
168
+ for (const [typeName, set1] of ids1.entries()) {
169
+ const set2 = ids2.get(typeName);
170
+ if (set2 === undefined) {
171
+ continue;
172
+ }
173
+
174
+ if (isNotDisjointFrom(set1, set2)) {
175
+ return true;
176
+ }
177
+ }
178
+ return false;
179
+ }
180
+
181
+ // TODO use a polyfill library
182
+ function isNotDisjointFrom<T>(set1: Set<T>, set2: Set<T>): boolean {
183
+ for (const id of set1) {
184
+ if (set2.has(id)) {
185
+ return true;
186
+ }
187
+ }
188
+ return false;
189
+ }
package/src/core/util.ts CHANGED
@@ -31,3 +31,29 @@ export type ArgumentValue =
31
31
  readonly kind: 'Object';
32
32
  readonly value: Arguments;
33
33
  };
34
+
35
+ export function isArray(value: unknown): value is readonly unknown[] {
36
+ return Array.isArray(value);
37
+ }
38
+
39
+ /**
40
+ * Creates a copy of the provided value, ensuring any nested objects have their
41
+ * keys sorted such that equivalent values would have identical JSON.stringify
42
+ * results.
43
+ */
44
+ export function stableCopy<T>(value: T): T {
45
+ if (value == null || typeof value !== 'object') {
46
+ return value;
47
+ }
48
+ if (isArray(value)) {
49
+ // @ts-ignore
50
+ return value.map(stableCopy);
51
+ }
52
+ const keys = Object.keys(value).sort();
53
+ const stable: { [index: string]: any } = {};
54
+ for (let i = 0; i < keys.length; i++) {
55
+ // @ts-ignore
56
+ stable[keys[i]] = stableCopy(value[keys[i]]);
57
+ }
58
+ return stable as any;
59
+ }
@@ -0,0 +1,79 @@
1
+ import type { ItemCleanupPair } from '@isograph/isograph-disposable-types/dist';
2
+ import { callSubscriptions } from './subscribe';
3
+ import {
4
+ type NetworkResponseObject,
5
+ type EncounteredIds,
6
+ normalizeData,
7
+ } from './cache';
8
+ import type { IsographEntrypoint, NormalizationAst } from './entrypoint';
9
+ import type {
10
+ UnknownTReadFromStore,
11
+ ExtractParameters,
12
+ FragmentReference,
13
+ } from './FragmentReference';
14
+ import {
15
+ type IsographEnvironment,
16
+ ROOT_ID,
17
+ getOrLoadReaderWithRefetchQueries,
18
+ } from './IsographEnvironment';
19
+ import { logMessage } from './logging';
20
+ import { retainQueryWithoutMakingNetworkRequest } from './makeNetworkRequest';
21
+ import { addNetworkResponseStoreLayer } from './optimisticProxy';
22
+
23
+ export function writeData<
24
+ TReadFromStore extends UnknownTReadFromStore,
25
+ TRawResponseType extends NetworkResponseObject,
26
+ TClientFieldValue,
27
+ >(
28
+ environment: IsographEnvironment,
29
+ entrypoint: IsographEntrypoint<
30
+ TReadFromStore,
31
+ TClientFieldValue,
32
+ NormalizationAst,
33
+ TRawResponseType
34
+ >,
35
+ data: TRawResponseType,
36
+ variables: ExtractParameters<TReadFromStore>,
37
+ ): ItemCleanupPair<FragmentReference<TReadFromStore, TClientFieldValue>> {
38
+ const encounteredIds: EncounteredIds = new Map();
39
+ environment.store = addNetworkResponseStoreLayer(environment.store);
40
+ normalizeData(
41
+ environment,
42
+ environment.store,
43
+ entrypoint.networkRequestInfo.normalizationAst.selections,
44
+ data,
45
+ variables,
46
+ { __link: ROOT_ID, __typename: entrypoint.concreteType },
47
+ encounteredIds,
48
+ );
49
+ logMessage(environment, () => ({
50
+ kind: 'AfterNormalization',
51
+ store: environment.store,
52
+ encounteredIds,
53
+ }));
54
+
55
+ callSubscriptions(environment, encounteredIds);
56
+
57
+ const { fieldName, readerArtifactKind, readerWithRefetchQueries } =
58
+ getOrLoadReaderWithRefetchQueries(
59
+ environment,
60
+ entrypoint.readerWithRefetchQueries,
61
+ );
62
+ const [networkRequest, disposeNetworkRequest] =
63
+ retainQueryWithoutMakingNetworkRequest(environment, entrypoint, variables);
64
+
65
+ return [
66
+ {
67
+ kind: 'FragmentReference',
68
+ readerWithRefetchQueries,
69
+ fieldName,
70
+ readerArtifactKind,
71
+ root: { __link: ROOT_ID, __typename: entrypoint.concreteType },
72
+ variables,
73
+ networkRequest,
74
+ },
75
+ () => {
76
+ disposeNetworkRequest();
77
+ },
78
+ ];
79
+ }
package/src/index.ts CHANGED
@@ -18,14 +18,14 @@ export {
18
18
  NOT_SET,
19
19
  } from './core/PromiseWrapper';
20
20
  export {
21
- callSubscriptions,
22
- subscribe,
23
21
  normalizeData,
24
22
  type NetworkResponseObject,
25
23
  type NetworkResponseValue,
26
24
  type NetworkResponseScalarValue,
27
25
  type EncounteredIds,
28
26
  } from './core/cache';
27
+ export { callSubscriptions, subscribe } from './core/subscribe';
28
+ export { writeData } from './core/writeData';
29
29
  export { makeNetworkRequest } from './core/makeNetworkRequest';
30
30
  export {
31
31
  ROOT_ID,
@@ -33,13 +33,12 @@ export {
33
33
  type DataTypeValue,
34
34
  type IsographEnvironment,
35
35
  type IsographNetworkFunction,
36
- type IsographStore,
36
+ type BaseStoreLayerData as IsographStore,
37
37
  type MissingFieldHandler,
38
38
  type StoreLink,
39
39
  type Link,
40
40
  type StoreRecord,
41
41
  type CacheMap,
42
- createIsographEnvironment,
43
42
  createIsographStore,
44
43
  type FieldCache,
45
44
  type Subscriptions,
@@ -85,7 +84,9 @@ export {
85
84
  type RefetchQueryNormalizationArtifactWrapper,
86
85
  type ExtractProps,
87
86
  type ExtractReadFromStore,
87
+ type ExtractClientFieldValue,
88
88
  type ExtractResolverResult,
89
+ type FragmentReferenceOfEntrypoint,
89
90
  type NetworkRequestInfo,
90
91
  type NormalizationInlineFragment,
91
92
  type ReaderWithRefetchQueries,
@@ -156,6 +157,7 @@ export {
156
157
  export { useLazyReference } from './react/useLazyReference';
157
158
  export { useRerenderOnChange } from './react/useRerenderOnChange';
158
159
  export { RenderAfterCommit__DO_NOT_USE } from './react/RenderAfterCommit__DO_NOT_USE';
160
+ export { createIsographEnvironment } from './react/createIsographEnvironment';
159
161
 
160
162
  export { useClientSideDefer } from './loadable-hooks/useClientSideDefer';
161
163
  export {
@@ -1,40 +1,18 @@
1
1
  import { useLazyDisposableState } from '@isograph/react-disposable-state';
2
2
  import { getOrCreateItemInSuspenseCache } from '../core/cache';
3
- import { FetchOptions } from '../core/check';
4
- import {
3
+ import type { FetchOptions } from '../core/check';
4
+ import type {
5
5
  ExtractParameters,
6
6
  FragmentReference,
7
- type UnknownTReadFromStore,
8
7
  } from '../core/FragmentReference';
9
- import { LoadableField } from '../core/reader';
8
+ import { type UnknownTReadFromStore } from '../core/FragmentReference';
9
+ import type { LoadableField } from '../core/reader';
10
10
  import { useIsographEnvironment } from '../react/IsographEnvironmentProvider';
11
11
 
12
- export function useClientSideDefer<
12
+ type ArgsWithoutProvidedArgs<
13
13
  TReadFromStore extends UnknownTReadFromStore,
14
- TResult,
15
- >(
16
- loadableField: LoadableField<
17
- TReadFromStore,
18
- TResult,
19
- ExtractParameters<TReadFromStore>
20
- >,
21
- args?: Record<PropertyKey, never>,
22
- fetchOptions?: FetchOptions<TResult>,
23
- ): { fragmentReference: FragmentReference<TReadFromStore, TResult> };
24
-
25
- export function useClientSideDefer<
26
- TReadFromStore extends UnknownTReadFromStore,
27
- TResult,
28
14
  TProvidedArgs extends object,
29
- >(
30
- loadableField: LoadableField<
31
- TReadFromStore,
32
- TResult,
33
- Omit<ExtractParameters<TReadFromStore>, keyof TProvidedArgs>
34
- >,
35
- args: Omit<ExtractParameters<TReadFromStore>, keyof TProvidedArgs>,
36
- fetchOptions?: FetchOptions<TResult>,
37
- ): { fragmentReference: FragmentReference<TReadFromStore, TResult> };
15
+ > = Omit<ExtractParameters<TReadFromStore>, keyof TProvidedArgs>;
38
16
 
39
17
  export function useClientSideDefer<
40
18
  TReadFromStore extends UnknownTReadFromStore,
@@ -46,9 +24,21 @@ export function useClientSideDefer<
46
24
  TResult,
47
25
  Omit<ExtractParameters<TReadFromStore>, keyof TProvidedArgs>
48
26
  >,
49
- args?: Omit<ExtractParameters<TReadFromStore>, keyof TProvidedArgs>,
50
- fetchOptions?: FetchOptions<TResult>,
27
+ ...maybeRequiredArgs: {} extends ArgsWithoutProvidedArgs<
28
+ TReadFromStore,
29
+ TProvidedArgs
30
+ >
31
+ ? [
32
+ args?: ArgsWithoutProvidedArgs<TReadFromStore, TProvidedArgs>,
33
+ fetchOptions?: FetchOptions<TResult, never>,
34
+ ]
35
+ : [
36
+ args: ArgsWithoutProvidedArgs<TReadFromStore, TProvidedArgs>,
37
+ fetchOptions?: FetchOptions<TResult, never>,
38
+ ]
51
39
  ): { fragmentReference: FragmentReference<TReadFromStore, TResult> } {
40
+ const [args, fetchOptions] = maybeRequiredArgs;
41
+
52
42
  const [id, loader] = loadableField(args, fetchOptions ?? {});
53
43
  const environment = useIsographEnvironment();
54
44
  const cache = getOrCreateItemInSuspenseCache(environment, id, loader);
@@ -57,3 +47,63 @@ export function useClientSideDefer<
57
47
 
58
48
  return { fragmentReference };
59
49
  }
50
+
51
+ // @ts-ignore
52
+ function tsTests() {
53
+ let neverArgs!: LoadableField<
54
+ {
55
+ parameters: Record<string, never>;
56
+ data: {};
57
+ },
58
+ unknown
59
+ >;
60
+
61
+ let optionalArgs!: LoadableField<
62
+ {
63
+ parameters: {
64
+ foo?: string;
65
+ };
66
+ data: {};
67
+ },
68
+ unknown
69
+ >;
70
+
71
+ let requiredArgs!: LoadableField<
72
+ {
73
+ parameters: {
74
+ foo: string;
75
+ };
76
+ data: {};
77
+ },
78
+ unknown
79
+ >;
80
+
81
+ useClientSideDefer(neverArgs);
82
+ useClientSideDefer(neverArgs, {});
83
+ useClientSideDefer(neverArgs, {
84
+ // @ts-expect-error
85
+ foo: 'bar',
86
+ });
87
+
88
+ useClientSideDefer(optionalArgs);
89
+ useClientSideDefer(optionalArgs, {});
90
+ useClientSideDefer(optionalArgs, {
91
+ foo: 'bar',
92
+ });
93
+ useClientSideDefer(optionalArgs, {
94
+ // @ts-expect-error
95
+ foo: 12,
96
+ });
97
+
98
+ // @ts-expect-error
99
+ useClientSideDefer(requiredArgs);
100
+ // @ts-expect-error
101
+ useClientSideDefer(requiredArgs, {});
102
+ useClientSideDefer(requiredArgs, {
103
+ foo: 'bar',
104
+ });
105
+ useClientSideDefer(requiredArgs, {
106
+ // @ts-expect-error
107
+ foo: 12,
108
+ });
109
+ }