@livestore/livestore 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. package/README.md +108 -0
  2. package/dist/.tsbuildinfo +1 -0
  3. package/dist/LiveRiffleStore.d.ts +42 -0
  4. package/dist/LiveRiffleStore.d.ts.map +1 -0
  5. package/dist/LiveRiffleStore.js +36 -0
  6. package/dist/LiveRiffleStore.js.map +1 -0
  7. package/dist/QueryCache.d.ts +20 -0
  8. package/dist/QueryCache.d.ts.map +1 -0
  9. package/dist/QueryCache.js +71 -0
  10. package/dist/QueryCache.js.map +1 -0
  11. package/dist/__tests__/react/fixture.d.ts +141 -0
  12. package/dist/__tests__/react/fixture.d.ts.map +1 -0
  13. package/dist/__tests__/react/fixture.js +72 -0
  14. package/dist/__tests__/react/fixture.js.map +1 -0
  15. package/dist/__tests__/react/useLiveStoreComponent.test.d.ts +2 -0
  16. package/dist/__tests__/react/useLiveStoreComponent.test.d.ts.map +1 -0
  17. package/dist/__tests__/react/useLiveStoreComponent.test.js +78 -0
  18. package/dist/__tests__/react/useLiveStoreComponent.test.js.map +1 -0
  19. package/dist/__tests__/react/useRiffleComponent.test.d.ts +2 -0
  20. package/dist/__tests__/react/useRiffleComponent.test.d.ts.map +1 -0
  21. package/dist/__tests__/react/useRiffleComponent.test.js +78 -0
  22. package/dist/__tests__/react/useRiffleComponent.test.js.map +1 -0
  23. package/dist/__tests__/reactive.test.d.ts +2 -0
  24. package/dist/__tests__/reactive.test.d.ts.map +1 -0
  25. package/dist/__tests__/reactive.test.js +167 -0
  26. package/dist/__tests__/reactive.test.js.map +1 -0
  27. package/dist/backends/base.d.ts +13 -0
  28. package/dist/backends/base.d.ts.map +1 -0
  29. package/dist/backends/base.js +53 -0
  30. package/dist/backends/base.js.map +1 -0
  31. package/dist/backends/index.d.ts +41 -0
  32. package/dist/backends/index.d.ts.map +1 -0
  33. package/dist/backends/index.js +38 -0
  34. package/dist/backends/index.js.map +1 -0
  35. package/dist/backends/noop.d.ts +18 -0
  36. package/dist/backends/noop.d.ts.map +1 -0
  37. package/dist/backends/noop.js +21 -0
  38. package/dist/backends/noop.js.map +1 -0
  39. package/dist/backends/tauri.d.ts +24 -0
  40. package/dist/backends/tauri.d.ts.map +1 -0
  41. package/dist/backends/tauri.js +48 -0
  42. package/dist/backends/tauri.js.map +1 -0
  43. package/dist/backends/utils/idb.d.ts +10 -0
  44. package/dist/backends/utils/idb.d.ts.map +1 -0
  45. package/dist/backends/utils/idb.js +58 -0
  46. package/dist/backends/utils/idb.js.map +1 -0
  47. package/dist/backends/web-in-memory.d.ts +24 -0
  48. package/dist/backends/web-in-memory.d.ts.map +1 -0
  49. package/dist/backends/web-in-memory.js +46 -0
  50. package/dist/backends/web-in-memory.js.map +1 -0
  51. package/dist/backends/web-worker.d.ts +17 -0
  52. package/dist/backends/web-worker.d.ts.map +1 -0
  53. package/dist/backends/web-worker.js +139 -0
  54. package/dist/backends/web-worker.js.map +1 -0
  55. package/dist/backends/web.d.ts +28 -0
  56. package/dist/backends/web.d.ts.map +1 -0
  57. package/dist/backends/web.js +64 -0
  58. package/dist/backends/web.js.map +1 -0
  59. package/dist/bounded-collections.d.ts +34 -0
  60. package/dist/bounded-collections.d.ts.map +1 -0
  61. package/dist/bounded-collections.js +103 -0
  62. package/dist/bounded-collections.js.map +1 -0
  63. package/dist/componentKey.d.ts +20 -0
  64. package/dist/componentKey.d.ts.map +1 -0
  65. package/dist/componentKey.js +3 -0
  66. package/dist/componentKey.js.map +1 -0
  67. package/dist/effect/LiveStore.d.ts +42 -0
  68. package/dist/effect/LiveStore.d.ts.map +1 -0
  69. package/dist/effect/LiveStore.js +36 -0
  70. package/dist/effect/LiveStore.js.map +1 -0
  71. package/dist/effect/index.d.ts +2 -0
  72. package/dist/effect/index.d.ts.map +1 -0
  73. package/dist/effect/index.js +2 -0
  74. package/dist/effect/index.js.map +1 -0
  75. package/dist/events.d.ts +7 -0
  76. package/dist/events.d.ts.map +1 -0
  77. package/dist/events.js +2 -0
  78. package/dist/events.js.map +1 -0
  79. package/dist/inMemoryDatabase.d.ts +65 -0
  80. package/dist/inMemoryDatabase.d.ts.map +1 -0
  81. package/dist/inMemoryDatabase.js +241 -0
  82. package/dist/inMemoryDatabase.js.map +1 -0
  83. package/dist/index.d.ts +20 -0
  84. package/dist/index.d.ts.map +1 -0
  85. package/dist/index.js +10 -0
  86. package/dist/index.js.map +1 -0
  87. package/dist/otel.d.ts +5 -0
  88. package/dist/otel.d.ts.map +1 -0
  89. package/dist/otel.js +17 -0
  90. package/dist/otel.js.map +1 -0
  91. package/dist/react/LiveStoreContext.d.ts +11 -0
  92. package/dist/react/LiveStoreContext.d.ts.map +1 -0
  93. package/dist/react/LiveStoreContext.js +10 -0
  94. package/dist/react/LiveStoreContext.js.map +1 -0
  95. package/dist/react/LiveStoreProvider.d.ts +21 -0
  96. package/dist/react/LiveStoreProvider.d.ts.map +1 -0
  97. package/dist/react/LiveStoreProvider.js +48 -0
  98. package/dist/react/LiveStoreProvider.js.map +1 -0
  99. package/dist/react/RiffleProvider.d.ts +21 -0
  100. package/dist/react/RiffleProvider.d.ts.map +1 -0
  101. package/dist/react/RiffleProvider.js +48 -0
  102. package/dist/react/RiffleProvider.js.map +1 -0
  103. package/dist/react/StoreContext.d.ts +11 -0
  104. package/dist/react/StoreContext.d.ts.map +1 -0
  105. package/dist/react/StoreContext.js +10 -0
  106. package/dist/react/StoreContext.js.map +1 -0
  107. package/dist/react/index.d.ts +7 -0
  108. package/dist/react/index.d.ts.map +1 -0
  109. package/dist/react/index.js +6 -0
  110. package/dist/react/index.js.map +1 -0
  111. package/dist/react/useGlobalQuery.d.ts +3 -0
  112. package/dist/react/useGlobalQuery.d.ts.map +1 -0
  113. package/dist/react/useGlobalQuery.js +25 -0
  114. package/dist/react/useGlobalQuery.js.map +1 -0
  115. package/dist/react/useGraphQL.d.ts +11 -0
  116. package/dist/react/useGraphQL.d.ts.map +1 -0
  117. package/dist/react/useGraphQL.js +68 -0
  118. package/dist/react/useGraphQL.js.map +1 -0
  119. package/dist/react/useLiveStoreComponent.d.ts +70 -0
  120. package/dist/react/useLiveStoreComponent.d.ts.map +1 -0
  121. package/dist/react/useLiveStoreComponent.js +261 -0
  122. package/dist/react/useLiveStoreComponent.js.map +1 -0
  123. package/dist/react/useRiffleComponent.d.ts +70 -0
  124. package/dist/react/useRiffleComponent.d.ts.map +1 -0
  125. package/dist/react/useRiffleComponent.js +261 -0
  126. package/dist/react/useRiffleComponent.js.map +1 -0
  127. package/dist/react/useRiffleJsonHook.d.ts +4 -0
  128. package/dist/react/useRiffleJsonHook.d.ts.map +1 -0
  129. package/dist/react/useRiffleJsonHook.js +21 -0
  130. package/dist/react/useRiffleJsonHook.js.map +1 -0
  131. package/dist/react/utils/useStateRefWithReactiveInput.d.ts +13 -0
  132. package/dist/react/utils/useStateRefWithReactiveInput.d.ts.map +1 -0
  133. package/dist/react/utils/useStateRefWithReactiveInput.js +38 -0
  134. package/dist/react/utils/useStateRefWithReactiveInput.js.map +1 -0
  135. package/dist/reactive.d.ts +140 -0
  136. package/dist/reactive.d.ts.map +1 -0
  137. package/dist/reactive.js +301 -0
  138. package/dist/reactive.js.map +1 -0
  139. package/dist/reactiveQueries/base-class.d.ts +24 -0
  140. package/dist/reactiveQueries/base-class.d.ts.map +1 -0
  141. package/dist/reactiveQueries/base-class.js +22 -0
  142. package/dist/reactiveQueries/base-class.js.map +1 -0
  143. package/dist/reactiveQueries/graphql.d.ts +25 -0
  144. package/dist/reactiveQueries/graphql.d.ts.map +1 -0
  145. package/dist/reactiveQueries/graphql.js +14 -0
  146. package/dist/reactiveQueries/graphql.js.map +1 -0
  147. package/dist/reactiveQueries/js.d.ts +19 -0
  148. package/dist/reactiveQueries/js.d.ts.map +1 -0
  149. package/dist/reactiveQueries/js.js +13 -0
  150. package/dist/reactiveQueries/js.js.map +1 -0
  151. package/dist/reactiveQueries/sql.d.ts +31 -0
  152. package/dist/reactiveQueries/sql.d.ts.map +1 -0
  153. package/dist/reactiveQueries/sql.js +28 -0
  154. package/dist/reactiveQueries/sql.js.map +1 -0
  155. package/dist/schema.d.ts +163 -0
  156. package/dist/schema.d.ts.map +1 -0
  157. package/dist/schema.js +92 -0
  158. package/dist/schema.js.map +1 -0
  159. package/dist/store.d.ts +175 -0
  160. package/dist/store.d.ts.map +1 -0
  161. package/dist/store.js +546 -0
  162. package/dist/store.js.map +1 -0
  163. package/dist/util.d.ts +24 -0
  164. package/dist/util.d.ts.map +1 -0
  165. package/dist/util.js +51 -0
  166. package/dist/util.js.map +1 -0
  167. package/package.json +52 -0
  168. package/src/QueryCache.ts +81 -0
  169. package/src/__tests__/react/fixture.tsx +106 -0
  170. package/src/__tests__/react/useLiveStoreComponent.test.tsx +111 -0
  171. package/src/__tests__/reactive.test.ts +227 -0
  172. package/src/ambient.d.ts +7 -0
  173. package/src/backends/base.ts +67 -0
  174. package/src/backends/index.ts +94 -0
  175. package/src/backends/noop.ts +32 -0
  176. package/src/backends/tauri.ts +74 -0
  177. package/src/backends/utils/idb.ts +71 -0
  178. package/src/backends/web-in-memory.ts +65 -0
  179. package/src/backends/web-worker.ts +176 -0
  180. package/src/backends/web.ts +96 -0
  181. package/src/bounded-collections.ts +112 -0
  182. package/src/componentKey.ts +9 -0
  183. package/src/effect/LiveStore.ts +123 -0
  184. package/src/effect/index.ts +7 -0
  185. package/src/events.ts +8 -0
  186. package/src/inMemoryDatabase.ts +347 -0
  187. package/src/index.ts +47 -0
  188. package/src/otel.ts +20 -0
  189. package/src/react/LiveStoreContext.ts +23 -0
  190. package/src/react/LiveStoreProvider.tsx +93 -0
  191. package/src/react/index.ts +11 -0
  192. package/src/react/useGlobalQuery.ts +40 -0
  193. package/src/react/useGraphQL.ts +113 -0
  194. package/src/react/useLiveStoreComponent.ts +493 -0
  195. package/src/react/utils/useStateRefWithReactiveInput.ts +51 -0
  196. package/src/reactive.ts +538 -0
  197. package/src/reactiveQueries/base-class.ts +49 -0
  198. package/src/reactiveQueries/graphql.ts +52 -0
  199. package/src/reactiveQueries/js.ts +38 -0
  200. package/src/reactiveQueries/sql.ts +65 -0
  201. package/src/schema.ts +219 -0
  202. package/src/store.ts +889 -0
  203. package/src/util.ts +59 -0
  204. package/tsconfig.json +15 -0
  205. package/vitest.config.js +13 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StoreContext.js","sourceRoot":"","sources":["../../src/react/StoreContext.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AAYzC,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,CAAC,aAAa,CAA4B,SAAS,CAAC,CAAA;AAErF,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAkB,EAAE;IAC1C,MAAM,YAAY,GAAG,UAAU,CAAC,YAAY,CAAC,CAAA;IAE7C,IAAI,YAAY,KAAK,SAAS,EAAE;QAC9B,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAA;KAC1E;IAED,OAAO,YAAY,CAAA;AACrB,CAAC,CAAA"}
@@ -0,0 +1,7 @@
1
+ export type { UseLiveStoreComponentProps as LiveStoreComponentConfig, ReactiveGraphQL, ReactiveSQL, Setters, } from './useLiveStoreComponent.js';
2
+ export { LiveStoreContext, useStore } from './LiveStoreContext.js';
3
+ export { LiveStoreProvider } from './LiveStoreProvider.js';
4
+ export { useLiveStoreComponent } from './useLiveStoreComponent.js';
5
+ export { useGraphQL } from './useGraphQL.js';
6
+ export { useGlobalQuery } from './useGlobalQuery.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,0BAA0B,IAAI,wBAAwB,EACtD,eAAe,EACf,WAAW,EACX,OAAO,GACR,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA"}
@@ -0,0 +1,6 @@
1
+ export { LiveStoreContext, useStore } from './LiveStoreContext.js';
2
+ export { LiveStoreProvider } from './LiveStoreProvider.js';
3
+ export { useLiveStoreComponent } from './useLiveStoreComponent.js';
4
+ export { useGraphQL } from './useGraphQL.js';
5
+ export { useGlobalQuery } from './useGlobalQuery.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { LiveStoreQuery, QueryResult } from '../store.js';
2
+ export declare const useGlobalQuery: <Q extends LiveStoreQuery>(query: Q) => QueryResult<Q>;
3
+ //# sourceMappingURL=useGlobalQuery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useGlobalQuery.d.ts","sourceRoot":"","sources":["../../src/react/useGlobalQuery.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE9D,eAAO,MAAM,cAAc,wDAiC1B,CAAA"}
@@ -0,0 +1,25 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { labelForKey } from '../componentKey.js';
3
+ import { TODO_REMOVE_trackLongRunningSpan } from '../otel.js';
4
+ export const useGlobalQuery = (query) => {
5
+ // We know the query has a result by the time we use it; so we can synchronously populate a default state
6
+ const [value, setValue] = useState(query.results$.result);
7
+ // Subscribe to future updates for this query
8
+ useEffect(() => {
9
+ return query.store.otel.tracer.startActiveSpan(`LiveStore:useGlobalQuery:${labelForKey(query.componentKey)}:${query.label}`, {}, query.store.otel.queriesSpanContext, (span) => {
10
+ TODO_REMOVE_trackLongRunningSpan(span);
11
+ const cancel = query.store.subscribe(query, (v) => {
12
+ // NOTE: we return a reference to the result object within LiveStore;
13
+ // this implies that app code must not mutate the results, or else
14
+ // there may be weird reactivity bugs.
15
+ return setValue(v);
16
+ }, undefined, { label: query.label });
17
+ return () => {
18
+ cancel();
19
+ span.end();
20
+ };
21
+ });
22
+ }, [query]);
23
+ return value;
24
+ };
25
+ //# sourceMappingURL=useGlobalQuery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useGlobalQuery.js","sourceRoot":"","sources":["../../src/react/useGlobalQuery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAE3C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAAE,gCAAgC,EAAE,MAAM,YAAY,CAAA;AAG7D,MAAM,CAAC,MAAM,cAAc,GAAG,CAA2B,KAAQ,EAAkB,EAAE;IACnF,yGAAyG;IACzG,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAiB,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;IAEzE,6CAA6C;IAC7C,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,CAC5C,4BAA4B,WAAW,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,KAAK,CAAC,KAAK,EAAE,EAC5E,EAAE,EACF,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,kBAAkB,EACnC,CAAC,IAAI,EAAE,EAAE;YACP,gCAAgC,CAAC,IAAI,CAAC,CAAA;YAEtC,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,SAAS,CAClC,KAAK,EACL,CAAC,CAAC,EAAE,EAAE;gBACJ,qEAAqE;gBACrE,kEAAkE;gBAClE,sCAAsC;gBACtC,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAA;YACpB,CAAC,EACD,SAAS,EACT,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CACvB,CAAA;YACD,OAAO,GAAG,EAAE;gBACV,MAAM,EAAE,CAAA;gBACR,IAAI,CAAC,GAAG,EAAE,CAAA;YACZ,CAAC,CAAA;QACH,CAAC,CACF,CAAA;IACH,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;IAEX,OAAO,KAAK,CAAA;AACd,CAAC,CAAA"}
@@ -0,0 +1,11 @@
1
+ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
2
+ import React from 'react';
3
+ import { type ComponentKeyConfig } from './useLiveStoreComponent.js';
4
+ export type UseLiveStoreComponentProps<TResult extends Record<string, any>, TVariables extends Record<string, any>> = {
5
+ query: DocumentNode<TResult, TVariables>;
6
+ variables: TVariables;
7
+ componentKey: ComponentKeyConfig;
8
+ reactDeps?: React.DependencyList;
9
+ };
10
+ export declare const useGraphQL: <TResult extends Record<string, any>, TVariables extends Record<string, any> = {}>({ query, variables, componentKey: componentKeyConfig, reactDeps, }: UseLiveStoreComponentProps<TResult, TVariables>) => Readonly<TResult>;
11
+ //# sourceMappingURL=useGraphQL.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useGraphQL.d.ts","sourceRoot":"","sources":["../../src/react/useGraphQL.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,IAAI,YAAY,EAAE,MAAM,mCAAmC,CAAA;AAG1F,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,OAAO,EAAE,KAAK,kBAAkB,EAAmB,MAAM,4BAA4B,CAAA;AAGrF,MAAM,MAAM,0BAA0B,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,UAAU,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI;IACpH,KAAK,EAAE,YAAY,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;IACxC,SAAS,EAAE,UAAU,CAAA;IACrB,YAAY,EAAE,kBAAkB,CAAA;IAChC,SAAS,CAAC,EAAE,KAAK,CAAC,cAAc,CAAA;CACjC,CAAA;AAWD,eAAO,MAAM,UAAU,8NAsFtB,CAAA"}
@@ -0,0 +1,68 @@
1
+ import * as otel from '@opentelemetry/api';
2
+ import { isEqual } from 'lodash-es';
3
+ import React from 'react';
4
+ import { labelForKey } from '../componentKey.js';
5
+ import { useStore } from './LiveStoreContext.js';
6
+ import { useComponentKey } from './useLiveStoreComponent.js';
7
+ import { useStateRefWithReactiveInput } from './utils/useStateRefWithReactiveInput.js';
8
+ /**
9
+ * This is needed because the `React.useMemo` call below, can sometimes be called multiple times 🤷,
10
+ * so we need to "cache" the fact that we've already started a span for this component.
11
+ * The map entry is being removed again in the `React.useEffect` call below.
12
+ */
13
+ const spanAlreadyStartedCache = new Map();
14
+ // TODO 1) figure out a way to make `variables` optional if the query doesn't have any variables (probably requires positional args)
15
+ // TODO 2) allow `.pipe` on the resulting query (possibly as a separate optional prop)
16
+ export const useGraphQL = ({ query, variables, componentKey: componentKeyConfig, reactDeps = [], }) => {
17
+ const componentKey = useComponentKey(componentKeyConfig, reactDeps);
18
+ const { store } = useStore();
19
+ const componentKeyLabel = React.useMemo(() => labelForKey(componentKey), [componentKey]);
20
+ // The following `React.useMemo` and `React.useEffect` calls are used to start and end a span for the lifetime of this component.
21
+ const { span, otelCtx } = React.useMemo(() => {
22
+ const existingSpan = spanAlreadyStartedCache.get(componentKeyLabel);
23
+ if (existingSpan !== undefined)
24
+ return existingSpan;
25
+ const span = store.otel.tracer.startSpan(`LiveStore:useGraphQL:${componentKeyLabel}`, {}, store.otel.queriesSpanContext);
26
+ const otelCtx = otel.trace.setSpan(otel.context.active(), span);
27
+ spanAlreadyStartedCache.set(componentKeyLabel, { span, otelCtx });
28
+ return { span, otelCtx };
29
+ }, [componentKeyLabel, store.otel.queriesSpanContext, store.otel.tracer]);
30
+ React.useEffect(() => () => {
31
+ spanAlreadyStartedCache.delete(componentKeyLabel);
32
+ span.end();
33
+ }, [componentKeyLabel, span]);
34
+ const makeLiveStoreQuery = React.useCallback(() => store.queryGraphQL(query, () => variables ?? {}, { componentKey }, otelCtx),
35
+ // NOTE: we don't include the queries function passed in by the user here;
36
+ // the reason is that we don't want to force them to memoize that function.
37
+ // Instead, we just assume that the function always has the same contents.
38
+ // This makes sense for LiveStore because the component config should be static.
39
+ // TODO: document this and consider whether it's the right API surface.
40
+ // eslint-disable-next-line react-hooks/exhaustive-deps
41
+ [componentKey, store]);
42
+ // TODO get rid of the temporary query workaround
43
+ const initialQueryResults = React.useMemo(() => store.inTempQueryContext(() => makeLiveStoreQuery().results$.result), [makeLiveStoreQuery, store]);
44
+ const [queryResultsRef, setQueryResults_] = useStateRefWithReactiveInput(initialQueryResults);
45
+ React.useEffect(() => {
46
+ const liveStoreQuery = makeLiveStoreQuery();
47
+ const unsubscribe = store.subscribe(liveStoreQuery, (results) => {
48
+ if (isEqual(results, queryResultsRef.current) === false) {
49
+ setQueryResults_(results);
50
+ }
51
+ }, undefined, { label: `useGraphQL:query:subscribe:${liveStoreQuery.label}` });
52
+ return () => {
53
+ unsubscribe();
54
+ };
55
+ // NOTE `setQueryResults_` from the deps array as it seems to cause an infinite loop
56
+ // This should probably be improved
57
+ // eslint-disable-next-line react-hooks/exhaustive-deps
58
+ }, [
59
+ otelCtx,
60
+ makeLiveStoreQuery,
61
+ // setQueryResults_,
62
+ store,
63
+ ]);
64
+ // Very important: remove any queries / other resources associated w/ this component
65
+ React.useEffect(() => () => store.unmountComponent(componentKey), [store, componentKey]);
66
+ return queryResultsRef.current;
67
+ };
68
+ //# sourceMappingURL=useGraphQL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useGraphQL.js","sourceRoot":"","sources":["../../src/react/useGraphQL.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
2
+ import { type LiteralUnion } from '@livestore/utils';
3
+ import type { DependencyList } from 'react';
4
+ import React from 'react';
5
+ import type { ComponentKey } from '../componentKey.js';
6
+ import type { GetAtom } from '../reactive.js';
7
+ import type { LiveStoreGraphQLQuery } from '../reactiveQueries/graphql.js';
8
+ import type { LiveStoreJSQuery } from '../reactiveQueries/js.js';
9
+ import type { LiveStoreSQLQuery } from '../reactiveQueries/sql.js';
10
+ import type { ComponentStateSchema } from '../schema.js';
11
+ import type { BaseGraphQLContext, LiveStoreQuery, QueryResult } from '../store.js';
12
+ export interface QueryDefinitions {
13
+ [queryName: string]: LiveStoreQuery;
14
+ }
15
+ export type QueryResults<TQuery> = {
16
+ [queryName in keyof TQuery]: QueryResult<TQuery[queryName]>;
17
+ };
18
+ export type ReactiveSQL = <TResult>(genQuery: (get: GetAtom) => string, queriedTables: string[]) => LiveStoreSQLQuery<TResult>;
19
+ export type ReactiveGraphQL = <TResult extends Record<string, any>, TVariables extends Record<string, any>, TContext extends BaseGraphQLContext>(query: DocumentNode<TResult, TVariables>, genVariableValues: (get: GetAtom) => TVariables, label?: string) => LiveStoreGraphQLQuery<TResult, TVariables, TContext>;
20
+ type RegisterSubscription = <TQuery extends LiveStoreQuery>(query: TQuery, onNewValue: (value: QueryResult<TQuery>) => void, onUnsubscribe?: () => void) => void;
21
+ type GenQueries<TQueries, TStateResult> = (args: {
22
+ rxSQL: ReactiveSQL;
23
+ rxGraphQL: ReactiveGraphQL;
24
+ globalQueries: QueryDefinitions;
25
+ state$: LiveStoreJSQuery<TStateResult>;
26
+ /** Registers a subscription */
27
+ subscribe: RegisterSubscription;
28
+ isTemporaryQuery: boolean;
29
+ }) => TQueries;
30
+ export type UseLiveStoreComponentProps<TQueries, TComponentState> = {
31
+ stateSchema?: ComponentStateSchema<TComponentState>;
32
+ queries?: GenQueries<TQueries, TComponentState>;
33
+ reactDeps?: React.DependencyList;
34
+ componentKey: ComponentKeyConfig;
35
+ };
36
+ export type ComponentKeyConfig = {
37
+ /**
38
+ * Name of the Component
39
+ *
40
+ * TODO we should eventually derive this info automatically from the component (TBD how though...)
41
+ */
42
+ name: string;
43
+ id: LiteralUnion<'singleton' | '__ephemeral__', string>;
44
+ };
45
+ type ComponentState = {
46
+ /** Equivalent to `componentKey.key` */
47
+ id: string;
48
+ [key: string]: string | number | boolean | null;
49
+ };
50
+ type UseLiveStoreJsonState<TState> = <TResult>(jsonStringKey: keyof TState, parse?: (_: unknown) => TResult) => [value: TResult, setValue: (newVal: TResult | ((prevVal: TResult) => TResult)) => void];
51
+ /**
52
+ * Create reactive queries within a component.
53
+ * @param config.queries A function that returns a map of named reactive queries.
54
+ * @param config.componentKey A function that returns a unique key for this component.
55
+ * @param config.reactDeps A list of React-level dependencies that will refresh the queries.
56
+ */
57
+ export declare const useLiveStoreComponent: <TComponentState extends ComponentState, TQueries extends QueryDefinitions>({ stateSchema: stateSchema_, queries, componentKey: componentKeyConfig, reactDeps, }: UseLiveStoreComponentProps<TQueries, TComponentState>) => {
58
+ queryResults: QueryResults<TQueries>;
59
+ state: TComponentState;
60
+ setState: Setters<TComponentState>;
61
+ useLiveStoreJsonState: UseLiveStoreJsonState<TComponentState>;
62
+ };
63
+ export type Setters<TComponentState> = {
64
+ [k in keyof TComponentState]: (newValue: TComponentState[k]) => void;
65
+ } & {
66
+ setMany: (newValues: Partial<TComponentState>) => void;
67
+ };
68
+ export declare const useComponentKey: ({ name, id }: ComponentKeyConfig, deps?: DependencyList) => ComponentKey;
69
+ export {};
70
+ //# sourceMappingURL=useLiveStoreComponent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLiveStoreComponent.d.ts","sourceRoot":"","sources":["../../src/react/useLiveStoreComponent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,261 @@
1
+ import { omit, shouldNeverHappen } from '@livestore/utils';
2
+ import * as otel from '@opentelemetry/api';
3
+ import { isEqual, mapValues } from 'lodash-es';
4
+ import React from 'react';
5
+ import { v4 as uuid } from 'uuid';
6
+ import { labelForKey, tableNameForComponentKey } from '../componentKey.js';
7
+ import { sql } from '../util.js';
8
+ import { useStore } from './LiveStoreContext.js';
9
+ import { useStateRefWithReactiveInput } from './utils/useStateRefWithReactiveInput.js';
10
+ /**
11
+ * This is needed because the `React.useMemo` call below, can sometimes be called multiple times 🤷,
12
+ * so we need to "cache" the fact that we've already started a span for this component.
13
+ * The map entry is being removed again in the `React.useEffect` call below.
14
+ */
15
+ const spanAlreadyStartedCache = new Map();
16
+ /**
17
+ * Create reactive queries within a component.
18
+ * @param config.queries A function that returns a map of named reactive queries.
19
+ * @param config.componentKey A function that returns a unique key for this component.
20
+ * @param config.reactDeps A list of React-level dependencies that will refresh the queries.
21
+ */
22
+ export const useLiveStoreComponent = ({ stateSchema: stateSchema_, queries = () => ({}), componentKey: componentKeyConfig, reactDeps = [], }) => {
23
+ // TODO we should clean up the state schema handling to remove this special handling for the `id` column
24
+ const stateSchema = React.useMemo(() => (stateSchema_ ? { ...stateSchema_, columns: omit(stateSchema_.columns, 'id') } : undefined), [stateSchema_]);
25
+ // performance.mark('useLiveStoreComponent:start')
26
+ const componentKey = useComponentKey(componentKeyConfig, reactDeps);
27
+ const { store, globalQueries } = useStore();
28
+ const componentKeyLabel = React.useMemo(() => labelForKey(componentKey), [componentKey]);
29
+ // The following `React.useMemo` and `React.useEffect` calls are used to start and end a span for the lifetime of this component.
30
+ const { span, otelCtx } = React.useMemo(() => {
31
+ const existingSpan = spanAlreadyStartedCache.get(componentKeyLabel);
32
+ if (existingSpan !== undefined)
33
+ return existingSpan;
34
+ const span = store.otel.tracer.startSpan(`LiveStore:useLiveStoreComponent:${componentKeyLabel}`, {}, store.otel.queriesSpanContext);
35
+ const otelCtx = otel.trace.setSpan(otel.context.active(), span);
36
+ spanAlreadyStartedCache.set(componentKeyLabel, { span, otelCtx });
37
+ return { span, otelCtx };
38
+ }, [componentKeyLabel, store.otel.queriesSpanContext, store.otel.tracer]);
39
+ React.useEffect(() => () => {
40
+ spanAlreadyStartedCache.delete(componentKeyLabel);
41
+ span.end();
42
+ }, [componentKeyLabel, span]);
43
+ const generateQueries = React.useCallback(({ state$, otelCtx, registerSubscription, isTemporaryQuery, }) => queries({
44
+ rxSQL: (genQuery, queriedTables) => store.querySQL(genQuery, queriedTables, undefined, componentKey, undefined, otelCtx),
45
+ rxGraphQL: (query, genVariableValues, label) => store.queryGraphQL(query, genVariableValues, { componentKey, label }, otelCtx),
46
+ globalQueries,
47
+ state$,
48
+ subscribe: registerSubscription,
49
+ isTemporaryQuery,
50
+ }),
51
+ // NOTE: we don't include the queries function passed in by the user here;
52
+ // the reason is that we don't want to force them to memoize that function.
53
+ // Instead, we just assume that the function always has the same contents.
54
+ // This makes sense for LiveStore because the component config should be static.
55
+ // TODO: document this and consider whether it's the right API surface.
56
+ // eslint-disable-next-line react-hooks/exhaustive-deps
57
+ [store, componentKey, globalQueries]);
58
+ const defaultComponentState = React.useMemo(() => {
59
+ const defaultState = (stateSchema === undefined ? {} : mapValues(stateSchema.columns, (c) => c.default));
60
+ defaultState.id = componentKeyConfig.id;
61
+ return defaultState;
62
+ }, [componentKeyConfig.id, stateSchema]);
63
+ // Step 1:
64
+ // Synchronously create state and queries for initial render pass.
65
+ // We do this in a temporary query context which cleans up after itself, making it idempotent
66
+ // TODO get rid of the temporary query workaround
67
+ const { initialComponentState, initialQueryResults } = React.useMemo(() => {
68
+ return store.otel.tracer.startActiveSpan('LiveStore:useLiveStoreComponent:initial', {}, otelCtx, (span) => {
69
+ const otelCtx = otel.trace.setSpan(otel.context.active(), span);
70
+ return store.inTempQueryContext(() => {
71
+ try {
72
+ // create state query
73
+ let stateQuery;
74
+ if (stateSchema === undefined) {
75
+ // TODO don't set up a query if there's no state schema (keeps the graph more clean)
76
+ stateQuery = store.queryJS(() => ({}), componentKey, undefined, otelCtx);
77
+ }
78
+ else {
79
+ const componentTableName = tableNameForComponentKey(componentKey);
80
+ const whereClause = componentKey._tag === 'singleton' ? '' : `where id = '${componentKey.id}'`;
81
+ stateQuery = store
82
+ .querySQL(() => sql `select * from ${componentTableName} ${whereClause} limit 1`, [componentTableName], undefined, componentKey, `localState:query:${componentKeyLabel}`, otelCtx)
83
+ .getFirstRow({ defaultValue: defaultComponentState });
84
+ }
85
+ const initialComponentState = stateQuery.results$.result;
86
+ const queries = generateQueries({
87
+ state$: stateQuery,
88
+ otelCtx,
89
+ registerSubscription: () => { },
90
+ isTemporaryQuery: true,
91
+ });
92
+ for (const [name, query] of Object.entries(queries)) {
93
+ query.label = name;
94
+ }
95
+ const initialQueryResults = mapValues(queries, (query) => query.results$.result);
96
+ return { initialComponentState, initialQueryResults };
97
+ }
98
+ finally {
99
+ span.end();
100
+ }
101
+ });
102
+ });
103
+ }, [store, otelCtx, stateSchema, generateQueries, componentKey, componentKeyLabel, defaultComponentState]);
104
+ // Now that we've computed the initial state synchronously,
105
+ // we can set up our useState calls w/ a default value populated...
106
+ const [componentStateRef, setComponentState_] = useStateRefWithReactiveInput(initialComponentState);
107
+ const [queryResultsRef, setQueryResults_] = useStateRefWithReactiveInput(initialQueryResults);
108
+ const setState = (stateSchema === undefined
109
+ ? {}
110
+ : // TODO: do we have a better type for the values that can go in SQLite?
111
+ mapValues(stateSchema.columns, (_, columnName) => (value) => {
112
+ // Don't update the state if it's the same as the value already seen in the component
113
+ if (componentStateRef.current[columnName] === value)
114
+ return;
115
+ if (['componentKey', 'columnNames'].includes(columnName)) {
116
+ shouldNeverHappen(`Can't use reserved column name ${columnName}`);
117
+ }
118
+ return store.applyEvent('updateComponentState', {
119
+ componentKey,
120
+ columnNames: [columnName],
121
+ [columnName]: value,
122
+ });
123
+ }));
124
+ setState.setMany = (columnValues) => {
125
+ // TODO use hashing instead
126
+ // Don't update the state if it's the same as the value already seen in the component
127
+ if (Object.entries(columnValues).every(([columnName, value]) => componentStateRef.current[columnName] === value)) {
128
+ return;
129
+ }
130
+ const columnNames = Object.keys(columnValues);
131
+ return store.applyEvent('updateComponentState', { componentKey, columnNames, ...columnValues });
132
+ };
133
+ // OK, now all the synchronous work is done;
134
+ // time to set up our long-running queries in an effect
135
+ React.useEffect(() => {
136
+ return store.otel.tracer.startActiveSpan('LiveStore:useLiveStoreComponent:long-running', { attributes: {} }, otelCtx, (span) => {
137
+ const otelCtx = otel.trace.setSpan(otel.context.active(), span);
138
+ const unsubs = [];
139
+ // create state query
140
+ let stateQuery;
141
+ if (stateSchema === undefined) {
142
+ stateQuery = store.queryJS(() => ({}), componentKey, undefined, otelCtx);
143
+ }
144
+ else {
145
+ const componentTableName = tableNameForComponentKey(componentKey);
146
+ insertRowForComponentInstance({ store, componentKey, stateSchema });
147
+ const whereClause = componentKey._tag === 'singleton' ? '' : `where id = '${componentKey.id}'`;
148
+ stateQuery = store
149
+ .querySQL(() => sql `select * from ${componentTableName} ${whereClause} limit 1`, [componentTableName], undefined, componentKey,
150
+ // TODO introduce a refresh "grouping" concept to associate related refreshes in the debugger UI
151
+ `localState:query:${componentKeyLabel}`, otelCtx)
152
+ .getFirstRow({ defaultValue: defaultComponentState });
153
+ }
154
+ unsubs.push(store.subscribe(stateQuery, (results) => {
155
+ if (isEqual(results, componentStateRef.current) === false) {
156
+ setComponentState_(results);
157
+ }
158
+ }, undefined, { label: `useLiveStoreComponent:localState:subscribe:${stateQuery.label}` }));
159
+ const registerSubscription = (query, callback, onUnsubscribe) => {
160
+ unsubs.push(store.subscribe(query, (results) => {
161
+ callback(results);
162
+ }, onUnsubscribe, { label: `useLiveStoreComponent:query:manual-subscribe:${query.label}` }));
163
+ };
164
+ const queries = generateQueries({ state$: stateQuery, otelCtx, registerSubscription, isTemporaryQuery: false });
165
+ // Use the name given to this query in the useQueries hook as its label
166
+ for (const [name, query] of Object.entries(queries)) {
167
+ query.label = name;
168
+ }
169
+ for (const [key, query] of Object.entries(queries)) {
170
+ unsubs.push(store.subscribe(query, (results) => {
171
+ const newQueryResults = { ...queryResultsRef.current, [key]: results };
172
+ if (isEqual(newQueryResults, queryResultsRef.current) === false) {
173
+ setQueryResults_(newQueryResults);
174
+ }
175
+ }, undefined, { label: `useLiveStoreComponent:query:subscribe:${query.label}` }));
176
+ }
177
+ return () => {
178
+ for (const unsub of unsubs) {
179
+ unsub();
180
+ }
181
+ span.end();
182
+ };
183
+ });
184
+ // NOTE excluding `setComponentState_` and `setQueryResults_` from the deps array as it seems to cause an infinite loop
185
+ // This should probably be improved
186
+ // eslint-disable-next-line react-hooks/exhaustive-deps
187
+ }, [
188
+ store,
189
+ componentKey,
190
+ stateSchema,
191
+ defaultComponentState,
192
+ generateQueries,
193
+ otelCtx,
194
+ componentStateRef,
195
+ // setComponentState_,
196
+ // setQueryResults_,
197
+ ]);
198
+ // Very important: remove any queries / other resources associated w/ this component
199
+ React.useEffect(() => () => store.unmountComponent(componentKey), [store, componentKey]);
200
+ // performance.mark('useLiveStoreComponent:end')
201
+ // performance.measure(`useLiveStoreComponent:${componentKey.type}`, 'useLiveStoreComponent:start', 'useLiveStoreComponent:end')
202
+ const state = componentStateRef.current;
203
+ const useLiveStoreJsonState = (jsonStringKey, parse = (_) => _) => {
204
+ const value = React.useMemo(() => {
205
+ return parse(JSON.parse(state[jsonStringKey]));
206
+ // eslint-disable-next-line react-hooks/exhaustive-deps
207
+ }, [state[jsonStringKey], parse]);
208
+ const setValue = React.useCallback((newValOrFn) => {
209
+ const newVal = typeof newValOrFn === 'function'
210
+ ? // NOTE we're using the ref instead of the value because we want to be sure
211
+ // we're using the latest value when the setter is called
212
+ newValOrFn(parse(JSON.parse(componentStateRef.current[jsonStringKey])))
213
+ : newValOrFn;
214
+ setState[jsonStringKey](JSON.stringify(newVal));
215
+ }, [parse, jsonStringKey]);
216
+ return [value, setValue];
217
+ };
218
+ return {
219
+ queryResults: queryResultsRef.current,
220
+ state,
221
+ setState,
222
+ useLiveStoreJsonState,
223
+ };
224
+ };
225
+ export const useComponentKey = ({ name, id }, deps = []) => React.useMemo(() => {
226
+ switch (id) {
227
+ case 'singleton': {
228
+ return { _tag: 'singleton', componentName: name, id: 'singleton' };
229
+ }
230
+ case '__ephemeral__': {
231
+ return { _tag: 'ephemeral', componentName: name, id: uuid() };
232
+ }
233
+ default: {
234
+ return { _tag: 'custom', componentName: name, id };
235
+ }
236
+ }
237
+ // eslint-disable-next-line react-hooks/exhaustive-deps
238
+ }, [...deps, id, name]);
239
+ /**
240
+ * Create a row storing the state for a component instance, if none exists yet.
241
+ * Initialized with default values, and keyed on the component key.
242
+ */
243
+ const insertRowForComponentInstance = ({ store, componentKey, stateSchema, }) => {
244
+ const columnNames = ['id', ...Object.keys(stateSchema.columns)];
245
+ const columnValues = columnNames.map((name) => `$${name}`).join(', ');
246
+ const tableName = tableNameForComponentKey(componentKey);
247
+ const insertQuery = sql `insert into ${tableName} (${columnNames.join(', ')}) select ${columnValues} where not exists(select 1 from ${tableName} where id = '${componentKey.id}')`;
248
+ void store.execute(insertQuery, {
249
+ id: componentKey.id,
250
+ ...mapValues(stateSchema.columns, (column) => prepareValueForSql(column.default ?? null)),
251
+ }, [tableName]);
252
+ };
253
+ const prepareValueForSql = (value) => {
254
+ if (typeof value === 'string' || typeof value === 'number' || value === null) {
255
+ return value;
256
+ }
257
+ else {
258
+ return value ? 1 : 0;
259
+ }
260
+ };
261
+ //# sourceMappingURL=useLiveStoreComponent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLiveStoreComponent.js","sourceRoot":"","sources":["../../src/react/useLiveStoreComponent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
2
+ import { type LiteralUnion } from '@overtone/utils';
3
+ import type { DependencyList } from 'react';
4
+ import React from 'react';
5
+ import type { ComponentKey } from '../componentKey.js';
6
+ import type { GetAtom } from '../reactive.js';
7
+ import type { RiffleGraphQLQuery } from '../reactiveQueries/graphql.js';
8
+ import type { RiffleJSQuery } from '../reactiveQueries/js.js';
9
+ import type { RiffleSQLQuery } from '../reactiveQueries/sql.js';
10
+ import type { ComponentStateSchema } from '../schema.js';
11
+ import type { BaseGraphQLContext, QueryResult, RiffleQuery } from '../store.js';
12
+ export interface QueryDefinitions {
13
+ [queryName: string]: RiffleQuery;
14
+ }
15
+ export type QueryResults<TQuery> = {
16
+ [queryName in keyof TQuery]: QueryResult<TQuery[queryName]>;
17
+ };
18
+ export type ReactiveSQL = <TResult>(genQuery: (get: GetAtom) => string, queriedTables: string[]) => RiffleSQLQuery<TResult>;
19
+ export type ReactiveGraphQL = <TResult extends Record<string, any>, TVariables extends Record<string, any>, TContext extends BaseGraphQLContext>(query: DocumentNode<TResult, TVariables>, genVariableValues: (get: GetAtom) => TVariables, label?: string) => RiffleGraphQLQuery<TResult, TVariables, TContext>;
20
+ type RegisterSubscription = <TQuery extends RiffleQuery>(query: TQuery, onNewValue: (value: QueryResult<TQuery>) => void, onUnsubscribe?: () => void) => void;
21
+ type GenQueries<TQueries, TStateResult> = (args: {
22
+ rxSQL: ReactiveSQL;
23
+ rxGraphQL: ReactiveGraphQL;
24
+ globalQueries: QueryDefinitions;
25
+ state$: RiffleJSQuery<TStateResult>;
26
+ /** Registers a subscription */
27
+ subscribe: RegisterSubscription;
28
+ isTemporaryQuery: boolean;
29
+ }) => TQueries;
30
+ export type UseRiffleComponentProps<TQueries, TComponentState> = {
31
+ stateSchema?: ComponentStateSchema<TComponentState>;
32
+ queries?: GenQueries<TQueries, TComponentState>;
33
+ reactDeps?: React.DependencyList;
34
+ componentKey: ComponentKeyConfig;
35
+ };
36
+ export type ComponentKeyConfig = {
37
+ /**
38
+ * Name of the Component
39
+ *
40
+ * TODO we should eventually derive this info automatically from the component (TBD how though...)
41
+ */
42
+ name: string;
43
+ id: LiteralUnion<'singleton' | '__ephemeral__', string>;
44
+ };
45
+ type ComponentState = {
46
+ /** Equivalent to `componentKey.key` */
47
+ id: string;
48
+ [key: string]: string | number | boolean | null;
49
+ };
50
+ type UseRiffleJsonState<TState> = <TResult>(jsonStringKey: keyof TState, parse?: (_: unknown) => TResult) => [value: TResult, setValue: (newVal: TResult | ((prevVal: TResult) => TResult)) => void];
51
+ /**
52
+ * Create reactive queries within a component.
53
+ * @param config.queries A function that returns a map of named reactive queries.
54
+ * @param config.componentKey A function that returns a unique key for this component.
55
+ * @param config.reactDeps A list of React-level dependencies that will refresh the queries.
56
+ */
57
+ export declare const useRiffleComponent: <TComponentState extends ComponentState, TQueries extends QueryDefinitions>({ stateSchema: stateSchema_, queries, componentKey: componentKeyConfig, reactDeps, }: UseRiffleComponentProps<TQueries, TComponentState>) => {
58
+ queryResults: QueryResults<TQueries>;
59
+ state: TComponentState;
60
+ setState: Setters<TComponentState>;
61
+ useRiffleJsonState: UseRiffleJsonState<TComponentState>;
62
+ };
63
+ export type Setters<TComponentState> = {
64
+ [k in keyof TComponentState]: (newValue: TComponentState[k]) => void;
65
+ } & {
66
+ setMany: (newValues: Partial<TComponentState>) => void;
67
+ };
68
+ export declare const useComponentKey: ({ name, id }: ComponentKeyConfig, deps?: DependencyList) => ComponentKey;
69
+ export {};
70
+ //# sourceMappingURL=useRiffleComponent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useRiffleComponent.d.ts","sourceRoot":"","sources":["../../src/react/useRiffleComponent.ts"],"names":[],"mappings":"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"}