@livestore/livestore 0.0.13 → 0.0.14

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 +18 -21
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/QueryCache.d.ts +1 -1
  4. package/dist/QueryCache.d.ts.map +1 -1
  5. package/dist/QueryCache.js.map +1 -1
  6. package/dist/__tests__/react/fixture.d.ts +5 -4
  7. package/dist/__tests__/react/fixture.d.ts.map +1 -1
  8. package/dist/__tests__/react/fixture.js +13 -14
  9. package/dist/__tests__/react/fixture.js.map +1 -1
  10. package/dist/__tests__/react/useComponentState.test.d.ts +2 -0
  11. package/dist/__tests__/react/useComponentState.test.d.ts.map +1 -0
  12. package/dist/__tests__/react/useComponentState.test.js +68 -0
  13. package/dist/__tests__/react/useComponentState.test.js.map +1 -0
  14. package/dist/__tests__/react/useLQuery.test.d.ts +2 -0
  15. package/dist/__tests__/react/useLQuery.test.d.ts.map +1 -0
  16. package/dist/__tests__/react/useLQuery.test.js +38 -0
  17. package/dist/__tests__/react/useLQuery.test.js.map +1 -0
  18. package/dist/__tests__/react/useLiveStoreComponent.test.js +4 -9
  19. package/dist/__tests__/react/useLiveStoreComponent.test.js.map +1 -1
  20. package/dist/__tests__/react/useQuery.test.d.ts +2 -0
  21. package/dist/__tests__/react/useQuery.test.d.ts.map +1 -0
  22. package/dist/__tests__/react/useQuery.test.js +33 -0
  23. package/dist/__tests__/react/useQuery.test.js.map +1 -0
  24. package/dist/__tests__/react/utils/extractStackInfoFromStackTrace.test.d.ts +2 -0
  25. package/dist/__tests__/react/utils/extractStackInfoFromStackTrace.test.d.ts.map +1 -0
  26. package/dist/__tests__/react/utils/extractStackInfoFromStackTrace.test.js +38 -0
  27. package/dist/__tests__/react/utils/extractStackInfoFromStackTrace.test.js.map +1 -0
  28. package/dist/__tests__/reactive.test.js +168 -95
  29. package/dist/__tests__/reactive.test.js.map +1 -1
  30. package/dist/__tests__/reactiveQueries/sql.test.d.ts +2 -0
  31. package/dist/__tests__/reactiveQueries/sql.test.d.ts.map +1 -0
  32. package/dist/__tests__/reactiveQueries/sql.test.js +337 -0
  33. package/dist/__tests__/reactiveQueries/sql.test.js.map +1 -0
  34. package/dist/effect/LiveStore.d.ts +3 -9
  35. package/dist/effect/LiveStore.d.ts.map +1 -1
  36. package/dist/effect/LiveStore.js +11 -7
  37. package/dist/effect/LiveStore.js.map +1 -1
  38. package/dist/inMemoryDatabase.d.ts +17 -21
  39. package/dist/inMemoryDatabase.d.ts.map +1 -1
  40. package/dist/inMemoryDatabase.js +2 -9
  41. package/dist/inMemoryDatabase.js.map +1 -1
  42. package/dist/index.d.ts +9 -7
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +7 -3
  45. package/dist/index.js.map +1 -1
  46. package/dist/migrations.d.ts +7 -0
  47. package/dist/migrations.d.ts.map +1 -1
  48. package/dist/migrations.js +18 -13
  49. package/dist/migrations.js.map +1 -1
  50. package/dist/react/LiveStoreProvider.d.ts +1 -3
  51. package/dist/react/LiveStoreProvider.d.ts.map +1 -1
  52. package/dist/react/LiveStoreProvider.js +13 -10
  53. package/dist/react/LiveStoreProvider.js.map +1 -1
  54. package/dist/react/index.d.ts +4 -4
  55. package/dist/react/index.d.ts.map +1 -1
  56. package/dist/react/index.js +3 -3
  57. package/dist/react/index.js.map +1 -1
  58. package/dist/react/useComponentState.d.ts +50 -0
  59. package/dist/react/useComponentState.d.ts.map +1 -0
  60. package/dist/react/useComponentState.js +248 -0
  61. package/dist/react/useComponentState.js.map +1 -0
  62. package/dist/react/useGlobalQuery.d.ts +2 -2
  63. package/dist/react/useGlobalQuery.d.ts.map +1 -1
  64. package/dist/react/useGlobalQuery.js +5 -2
  65. package/dist/react/useGlobalQuery.js.map +1 -1
  66. package/dist/react/useGraphQL.d.ts +5 -3
  67. package/dist/react/useGraphQL.d.ts.map +1 -1
  68. package/dist/react/useGraphQL.js +27 -7
  69. package/dist/react/useGraphQL.js.map +1 -1
  70. package/dist/react/useLiveStoreComponent.d.ts +14 -14
  71. package/dist/react/useLiveStoreComponent.d.ts.map +1 -1
  72. package/dist/react/useLiveStoreComponent.js +151 -91
  73. package/dist/react/useLiveStoreComponent.js.map +1 -1
  74. package/dist/react/useQuery.d.ts +3 -0
  75. package/dist/react/useQuery.d.ts.map +1 -0
  76. package/dist/react/useQuery.js +42 -0
  77. package/dist/react/useQuery.js.map +1 -0
  78. package/dist/react/useTemporaryQuery.d.ts +8 -0
  79. package/dist/react/useTemporaryQuery.d.ts.map +1 -0
  80. package/dist/react/useTemporaryQuery.js +17 -0
  81. package/dist/react/useTemporaryQuery.js.map +1 -0
  82. package/dist/react/utils/extractNamesFromStackTrace.d.ts +3 -0
  83. package/dist/react/utils/extractNamesFromStackTrace.d.ts.map +1 -0
  84. package/dist/react/utils/extractNamesFromStackTrace.js +40 -0
  85. package/dist/react/utils/extractNamesFromStackTrace.js.map +1 -0
  86. package/dist/react/utils/extractStackInfoFromStackTrace.d.ts +7 -0
  87. package/dist/react/utils/extractStackInfoFromStackTrace.d.ts.map +1 -0
  88. package/dist/react/utils/extractStackInfoFromStackTrace.js +40 -0
  89. package/dist/react/utils/extractStackInfoFromStackTrace.js.map +1 -0
  90. package/dist/reactive.d.ts +42 -48
  91. package/dist/reactive.d.ts.map +1 -1
  92. package/dist/reactive.js +293 -186
  93. package/dist/reactive.js.map +1 -1
  94. package/dist/reactiveQueries/base-class.d.ts +28 -20
  95. package/dist/reactiveQueries/base-class.d.ts.map +1 -1
  96. package/dist/reactiveQueries/base-class.js +25 -17
  97. package/dist/reactiveQueries/base-class.js.map +1 -1
  98. package/dist/reactiveQueries/graph.d.ts +10 -0
  99. package/dist/reactiveQueries/graph.d.ts.map +1 -0
  100. package/dist/reactiveQueries/graph.js +6 -0
  101. package/dist/reactiveQueries/graph.js.map +1 -0
  102. package/dist/reactiveQueries/graphql.d.ts +35 -18
  103. package/dist/reactiveQueries/graphql.d.ts.map +1 -1
  104. package/dist/reactiveQueries/graphql.js +91 -10
  105. package/dist/reactiveQueries/graphql.js.map +1 -1
  106. package/dist/reactiveQueries/js.d.ts +17 -13
  107. package/dist/reactiveQueries/js.d.ts.map +1 -1
  108. package/dist/reactiveQueries/js.js +31 -8
  109. package/dist/reactiveQueries/js.js.map +1 -1
  110. package/dist/reactiveQueries/sql.d.ts +22 -18
  111. package/dist/reactiveQueries/sql.d.ts.map +1 -1
  112. package/dist/reactiveQueries/sql.js +81 -16
  113. package/dist/reactiveQueries/sql.js.map +1 -1
  114. package/dist/schema.d.ts +0 -2
  115. package/dist/schema.d.ts.map +1 -1
  116. package/dist/schema.js +3 -6
  117. package/dist/schema.js.map +1 -1
  118. package/dist/storage/in-memory/index.d.ts +2 -2
  119. package/dist/storage/in-memory/index.d.ts.map +1 -1
  120. package/dist/storage/in-memory/index.js.map +1 -1
  121. package/dist/storage/index.d.ts +2 -2
  122. package/dist/storage/index.d.ts.map +1 -1
  123. package/dist/storage/tauri/index.d.ts +2 -2
  124. package/dist/storage/tauri/index.d.ts.map +1 -1
  125. package/dist/storage/tauri/index.js.map +1 -1
  126. package/dist/storage/web-worker/index.d.ts +4 -4
  127. package/dist/storage/web-worker/index.d.ts.map +1 -1
  128. package/dist/storage/web-worker/index.js +3 -5
  129. package/dist/storage/web-worker/index.js.map +1 -1
  130. package/dist/storage/web-worker/worker.js +2 -2
  131. package/dist/storage/web-worker/worker.js.map +1 -1
  132. package/dist/store.d.ts +19 -52
  133. package/dist/store.d.ts.map +1 -1
  134. package/dist/store.js +323 -266
  135. package/dist/store.js.map +1 -1
  136. package/dist/util.d.ts +3 -1
  137. package/dist/util.d.ts.map +1 -1
  138. package/dist/util.js +2 -0
  139. package/dist/util.js.map +1 -1
  140. package/package.json +2 -1
  141. package/src/QueryCache.ts +1 -1
  142. package/src/__tests__/react/fixture.tsx +21 -16
  143. package/src/__tests__/react/{useLiveStoreComponent.test.tsx → useComponentState.test.tsx} +9 -20
  144. package/src/__tests__/react/useQuery.test.tsx +48 -0
  145. package/src/__tests__/react/utils/extractStackInfoFromStackTrace.test.ts +40 -0
  146. package/src/__tests__/reactive.test.ts +194 -142
  147. package/src/__tests__/reactiveQueries/sql.test.ts +372 -0
  148. package/src/effect/LiveStore.ts +14 -18
  149. package/src/inMemoryDatabase.ts +22 -30
  150. package/src/index.ts +8 -6
  151. package/src/migrations.ts +39 -21
  152. package/src/react/LiveStoreProvider.tsx +13 -16
  153. package/src/react/index.ts +4 -8
  154. package/src/react/{useLiveStoreComponent.ts → useComponentState.ts} +98 -230
  155. package/src/react/useQuery.ts +58 -0
  156. package/src/react/useTemporaryQuery.ts +21 -0
  157. package/src/react/utils/extractStackInfoFromStackTrace.ts +47 -0
  158. package/src/reactive.ts +386 -267
  159. package/src/reactiveQueries/base-class.ts +61 -39
  160. package/src/reactiveQueries/graph.ts +15 -0
  161. package/src/reactiveQueries/graphql.ts +147 -31
  162. package/src/reactiveQueries/js.ts +54 -21
  163. package/src/reactiveQueries/sql.ts +128 -37
  164. package/src/schema.ts +2 -5
  165. package/src/storage/in-memory/index.ts +2 -2
  166. package/src/storage/index.ts +2 -2
  167. package/src/storage/tauri/index.ts +2 -2
  168. package/src/storage/web-worker/index.ts +6 -8
  169. package/src/storage/web-worker/worker.ts +2 -2
  170. package/src/store.ts +394 -418
  171. package/src/util.ts +8 -2
  172. package/dist/backends/base.d.ts +0 -13
  173. package/dist/backends/base.d.ts.map +0 -1
  174. package/dist/backends/base.js +0 -53
  175. package/dist/backends/base.js.map +0 -1
  176. package/dist/backends/in-memory/index.d.ts +0 -22
  177. package/dist/backends/in-memory/index.d.ts.map +0 -1
  178. package/dist/backends/in-memory/index.js +0 -45
  179. package/dist/backends/in-memory/index.js.map +0 -1
  180. package/dist/backends/index.d.ts +0 -41
  181. package/dist/backends/index.d.ts.map +0 -1
  182. package/dist/backends/index.js +0 -16
  183. package/dist/backends/index.js.map +0 -1
  184. package/dist/backends/tauri/index.d.ts +0 -21
  185. package/dist/backends/tauri/index.d.ts.map +0 -1
  186. package/dist/backends/tauri/index.js +0 -48
  187. package/dist/backends/tauri/index.js.map +0 -1
  188. package/dist/backends/utils/idb.d.ts +0 -10
  189. package/dist/backends/utils/idb.d.ts.map +0 -1
  190. package/dist/backends/utils/idb.js +0 -58
  191. package/dist/backends/utils/idb.js.map +0 -1
  192. package/dist/backends/web-worker/index.d.ts +0 -26
  193. package/dist/backends/web-worker/index.d.ts.map +0 -1
  194. package/dist/backends/web-worker/index.js +0 -63
  195. package/dist/backends/web-worker/index.js.map +0 -1
  196. package/dist/backends/web-worker/worker.d.ts +0 -17
  197. package/dist/backends/web-worker/worker.d.ts.map +0 -1
  198. package/dist/backends/web-worker/worker.js +0 -139
  199. package/dist/backends/web-worker/worker.js.map +0 -1
  200. package/dist/storage/base.d.ts +0 -10
  201. package/dist/storage/base.d.ts.map +0 -1
  202. package/dist/storage/base.js +0 -14
  203. package/dist/storage/base.js.map +0 -1
  204. package/src/react/useGlobalQuery.ts +0 -37
  205. package/src/react/useGraphQL.ts +0 -112
package/dist/store.js CHANGED
@@ -1,247 +1,294 @@
1
1
  import { assertNever, makeNoopSpan, makeNoopTracer, shouldNeverHappen } from '@livestore/utils';
2
2
  import { identity } from '@livestore/utils/effect';
3
3
  import * as otel from '@opentelemetry/api';
4
- import * as graphql from 'graphql';
5
- import { uniqueId } from 'lodash-es';
6
- import * as ReactDOM from 'react-dom';
7
- import initSqlite3Wasm from 'sqlite-esm';
8
4
  import { v4 as uuid } from 'uuid';
9
5
  import { tableNameForComponentKey } from './componentKey.js';
10
6
  import { InMemoryDatabase } from './inMemoryDatabase.js';
11
7
  import { migrateDb } from './migrations.js';
12
8
  import { getDurationMsFromSpan } from './otel.js';
13
- import { ReactiveGraph } from './reactive.js';
14
- import { LiveStoreGraphQLQuery } from './reactiveQueries/graphql.js';
15
- import { LiveStoreJSQuery } from './reactiveQueries/js.js';
16
- import { LiveStoreSQLQuery } from './reactiveQueries/sql.js';
9
+ import { dbGraph } from './reactiveQueries/graph.js';
17
10
  import { componentStateTables } from './schema.js';
18
- import { isPromise, sql } from './util.js';
19
- export const RESET_DB_LOCAL_STORAGE_KEY = 'livestore-reset';
20
- const globalComponentKey = { _tag: 'singleton', componentName: '__global', id: 'singleton' };
11
+ import { isPromise, prepareBindValues, sql } from './util.js';
12
+ export const globalComponentKey = { _tag: 'singleton', componentName: '__global', id: 'singleton' };
21
13
  export class Store {
22
- constructor({ db, schema, storage, graphQLOptions, otelTracer, otelRootSpanContext, }) {
14
+ constructor({ db, dbProxy, schema, storage, graphQLOptions, otelTracer, otelRootSpanContext, }) {
23
15
  /**
24
16
  * Creates a reactive LiveStore SQL query
25
17
  *
26
18
  * NOTE The query is actually running (even if no one has subscribed to it yet) and will be kept up to date.
27
19
  */
28
- this.querySQL = (genQueryString, { queriedTables, bindValues, componentKey, label, otelContext = otel.context.active(), }) => this.otel.tracer.startActiveSpan('querySQL', // NOTE span name will be overridden further down
29
- { attributes: { label } }, otelContext, (span) => {
30
- const otelContext = otel.trace.setSpan(otel.context.active(), span);
31
- const queryString$ = this.graph.makeThunk((get, addDebugInfo) => {
32
- const queryString = genQueryString(get);
33
- addDebugInfo({ _tag: 'js', label: `${label}:queryString`, query: queryString });
34
- return queryString;
35
- }, { label: `${label}:queryString`, meta: { liveStoreThunkType: 'sqlQueryString' } }, otelContext);
36
- label = label ?? queryString$.result;
37
- span.updateName(`querySQL:${label}`);
38
- const queryLabel = `${label}:results` + (this.temporaryQueries ? ':temp' : '');
39
- const results$ = this.graph.makeThunk((get, addDebugInfo) => this.otel.tracer.startActiveSpan('sql', // NOTE span name will be overridden further down
40
- {}, otelContext, (span) => {
41
- try {
42
- const otelContext = otel.trace.setSpan(otel.context.active(), span);
43
- // Establish a reactive dependency on the tables used in the query
44
- for (const tableName of queriedTables) {
45
- const tableRef = this.tableRefs[tableName] ?? shouldNeverHappen(`No table ref found for ${tableName}`);
46
- get(tableRef);
47
- }
48
- const sqlString = get(queryString$);
49
- span.setAttribute('sql.query', sqlString);
50
- span.updateName(`sql:${sqlString.slice(0, 50)}`);
51
- const results = this.inMemoryDB.select(sqlString, { queriedTables, bindValues, otelContext });
52
- span.setAttribute('sql.rowsCount', results.length);
53
- addDebugInfo({ _tag: 'sql', label: label ?? '', query: sqlString });
54
- return results;
55
- }
56
- finally {
57
- span.end();
58
- }
59
- }), { label: queryLabel }, otelContext);
60
- const query = new LiveStoreSQLQuery({
61
- label,
62
- queryString$,
63
- results$,
64
- componentKey: componentKey ?? globalComponentKey,
65
- store: this,
66
- otelContext,
67
- });
68
- this.activeQueries.add(query);
69
- // TODO get rid of temporary query workaround
70
- if (this.temporaryQueries !== undefined) {
71
- this.temporaryQueries.add(query);
72
- }
73
- // NOTE we are not ending the span here but in the query `destroy` method
74
- return query;
75
- });
76
- this.queryJS = (genResults, { componentKey = globalComponentKey, label = `js${uniqueId()}`, otelContext = otel.context.active(), }) => this.otel.tracer.startActiveSpan(`queryJS:${label}`, { attributes: { label } }, otelContext, (span) => {
77
- const otelContext = otel.trace.setSpan(otel.context.active(), span);
78
- const queryLabel = `${label}:results` + (this.temporaryQueries ? ':temp' : '');
79
- const results$ = this.graph.makeThunk((get, addDebugInfo) => {
80
- addDebugInfo({ _tag: 'js', label, query: genResults.toString() });
81
- return genResults(get);
82
- }, { label: queryLabel, meta: { liveStoreThunkType: 'jsResults' } }, otelContext);
83
- const query = new LiveStoreJSQuery({
84
- label,
85
- results$,
86
- componentKey,
87
- store: this,
88
- otelContext,
89
- });
90
- this.activeQueries.add(query);
91
- // TODO get rid of temporary query workaround
92
- if (this.temporaryQueries !== undefined) {
93
- this.temporaryQueries.add(query);
94
- }
95
- // NOTE we are not ending the span here but in the query `destroy` method
96
- return query;
97
- });
98
- this.queryGraphQL = (document, genVariableValues, { componentKey, label, otelContext = otel.context.active(), }) => this.otel.tracer.startActiveSpan(`queryGraphQL:`, // NOTE span name will be overridden further down
99
- {}, otelContext, (span) => {
100
- const otelContext = otel.trace.setSpan(otel.context.active(), span);
101
- if (this.graphQLContext === undefined) {
102
- return shouldNeverHappen("Can't run a GraphQL query on a store without GraphQL context");
103
- }
104
- const labelWithDefault = label ?? graphql.getOperationAST(document)?.name?.value ?? 'graphql';
105
- span.updateName(`queryGraphQL:${labelWithDefault}`);
106
- const variableValues$ = this.graph.makeThunk(genVariableValues, { label: `${labelWithDefault}:variableValues`, meta: { liveStoreThunkType: 'graphqlVariableValues' } }, otelContext);
107
- const resultsLabel = `${labelWithDefault}:results` + (this.temporaryQueries ? ':temp' : '');
108
- const results$ = this.graph.makeThunk((get, addDebugInfo) => {
109
- const variableValues = get(variableValues$);
110
- const { result, queriedTables } = this.queryGraphQLOnce(document, variableValues, otelContext);
111
- // Add dependencies on any tables that were used
112
- for (const tableName of queriedTables) {
113
- const tableRef = this.tableRefs[tableName];
114
- assertNever(tableRef !== undefined, `No table ref found for ${tableName}`);
115
- get(tableRef);
116
- }
117
- addDebugInfo({ _tag: 'graphql', label: resultsLabel, query: graphql.print(document) });
118
- return result;
119
- }, { label: resultsLabel, meta: { liveStoreThunkType: 'graphqlResults' } }, otelContext);
120
- const query = new LiveStoreGraphQLQuery({
121
- document,
122
- context: this.graphQLContext,
123
- results$,
124
- componentKey,
125
- label: labelWithDefault,
126
- store: this,
127
- otelContext,
128
- });
129
- this.activeQueries.add(query);
130
- // TODO get rid of temporary query workaround
131
- if (this.temporaryQueries !== undefined) {
132
- this.temporaryQueries.add(query);
133
- }
134
- // NOTE we are not ending the span here but in the query `destroy` method
135
- return query;
136
- });
137
- this.queryGraphQLOnce = (document, variableValues, otelContext = this.otel.queriesSpanContext) => {
138
- const schema = this.graphQLSchema ?? shouldNeverHappen("Can't run a GraphQL query on a store without GraphQL schema");
139
- const context = this.graphQLContext ?? shouldNeverHappen("Can't run a GraphQL query on a store without GraphQL context");
140
- const tracer = this.otel.tracer;
141
- const operationName = graphql.getOperationAST(document)?.name?.value;
142
- return tracer.startActiveSpan(`executeGraphQLQuery: ${operationName}`, {}, otelContext, (span) => {
143
- try {
144
- span.setAttribute('graphql.variables', JSON.stringify(variableValues));
145
- span.setAttribute('graphql.query', graphql.print(document));
146
- context.queriedTables.clear();
147
- context.otelContext = otel.trace.setSpan(otel.context.active(), span);
148
- const res = graphql.executeSync({
149
- document,
150
- contextValue: context,
151
- schema: schema,
152
- variableValues,
153
- });
154
- // TODO track number of nested SQL queries via Otel + debug info
155
- if (res.errors) {
156
- span.setStatus({ code: otel.SpanStatusCode.ERROR, message: 'GraphQL error' });
157
- span.setAttribute('graphql.error', res.errors.join('\n'));
158
- span.setAttribute('graphql.error-detail', JSON.stringify(res.errors));
159
- console.error(`graphql error (${operationName})`, res.errors);
160
- }
161
- return { result: res.data, queriedTables: Array.from(context.queriedTables.values()) };
162
- }
163
- finally {
164
- span.end();
165
- }
166
- });
167
- };
20
+ // querySQL = <TResult>(
21
+ // genQueryString: string | ((get: GetAtomResult) => string),
22
+ // {
23
+ // queriedTables,
24
+ // bindValues,
25
+ // componentKey,
26
+ // label,
27
+ // otelContext = otel.context.active(),
28
+ // }: {
29
+ // /**
30
+ // * List of tables that are queried in this query;
31
+ // * used to determine reactive dependencies.
32
+ // *
33
+ // * NOTE In the future we want to auto-generate this via parsing the query
34
+ // */
35
+ // queriedTables: string[]
36
+ // bindValues?: Bindable | undefined
37
+ // componentKey?: ComponentKey | undefined
38
+ // label?: string | undefined
39
+ // otelContext?: otel.Context
40
+ // },
41
+ // ): LiveStoreSQLQuery<TResult> =>
42
+ // this.otel.tracer.startActiveSpan(
43
+ // 'querySQL', // NOTE span name will be overridden further down
44
+ // { attributes: { label } },
45
+ // otelContext,
46
+ // (span) => {
47
+ // const otelContext = otel.trace.setSpan(otel.context.active(), span)
48
+ // const queryString$ = this.graph.makeThunk(
49
+ // (get, addDebugInfo) => {
50
+ // if (typeof genQueryString === 'function') {
51
+ // const queryString = genQueryString(makeGetAtomResult(get))
52
+ // addDebugInfo({ _tag: 'js', label: `${label}:queryString`, query: queryString })
53
+ // return queryString
54
+ // } else {
55
+ // return genQueryString
56
+ // }
57
+ // },
58
+ // { label: `${label}:queryString`, meta: { liveStoreThunkType: 'sqlQueryString' } },
59
+ // otelContext,
60
+ // )
61
+ // label = label ?? queryString$.result
62
+ // span.updateName(`querySQL:${label}`)
63
+ // const queryLabel = `${label}:results` + (this.temporaryQueries ? ':temp' : '')
64
+ // const results$ = this.graph.makeThunk<ReadonlyArray<TResult>>(
65
+ // (get, addDebugInfo) =>
66
+ // this.otel.tracer.startActiveSpan(
67
+ // 'sql:', // NOTE span name will be overridden further down
68
+ // {},
69
+ // otelContext,
70
+ // (span) => {
71
+ // try {
72
+ // const otelContext = otel.trace.setSpan(otel.context.active(), span)
73
+ // // Establish a reactive dependency on the tables used in the query
74
+ // for (const tableName of queriedTables) {
75
+ // const tableRef =
76
+ // this.tableRefs[tableName] ?? shouldNeverHappen(`No table ref found for ${tableName}`)
77
+ // get(tableRef)
78
+ // }
79
+ // const sqlString = get(queryString$)
80
+ // span.setAttribute('sql.query', sqlString)
81
+ // span.updateName(`sql:${sqlString.slice(0, 50)}`)
82
+ // const results = this.inMemoryDB.select<TResult>(sqlString, {
83
+ // queriedTables,
84
+ // bindValues: bindValues ? prepareBindValues(bindValues, sqlString) : undefined,
85
+ // otelContext,
86
+ // })
87
+ // span.setAttribute('sql.rowsCount', results.length)
88
+ // addDebugInfo({ _tag: 'sql', label: label ?? '', query: sqlString })
89
+ // return results
90
+ // } finally {
91
+ // span.end()
92
+ // }
93
+ // },
94
+ // ),
95
+ // { label: queryLabel },
96
+ // otelContext,
97
+ // )
98
+ // const query = new LiveStoreSQLQuery<TResult>({
99
+ // label,
100
+ // queryString$,
101
+ // results$,
102
+ // componentKey: componentKey ?? globalComponentKey,
103
+ // store: this,
104
+ // otelContext,
105
+ // })
106
+ // this.activeQueries.add(query)
107
+ // // TODO get rid of temporary query workaround
108
+ // if (this.temporaryQueries !== undefined) {
109
+ // this.temporaryQueries.add(query)
110
+ // }
111
+ // // NOTE we are not ending the span here but in the query `destroy` method
112
+ // return query
113
+ // },
114
+ // )
115
+ // queryJS = <TResult>(
116
+ // genResults: (get: GetAtomResult) => TResult,
117
+ // {
118
+ // componentKey = globalComponentKey,
119
+ // label = `js${uniqueId()}`,
120
+ // otelContext = otel.context.active(),
121
+ // }: { componentKey?: ComponentKey; label?: string; otelContext?: otel.Context },
122
+ // ): LiveStoreJSQuery<TResult> =>
123
+ // this.otel.tracer.startActiveSpan(`queryJS:${label}`, { attributes: { label } }, otelContext, (span) => {
124
+ // const otelContext = otel.trace.setSpan(otel.context.active(), span)
125
+ // const queryLabel = `${label}:results` + (this.temporaryQueries ? ':temp' : '')
126
+ // const results$ = this.graph.makeThunk(
127
+ // (get, addDebugInfo) => {
128
+ // addDebugInfo({ _tag: 'js', label, query: genResults.toString() })
129
+ // return genResults(makeGetAtomResult(get))
130
+ // },
131
+ // { label: queryLabel, meta: { liveStoreThunkType: 'jsResults' } },
132
+ // otelContext,
133
+ // )
134
+ // // const query = new LiveStoreJSQuery<TResult>({
135
+ // // label,
136
+ // // results$,
137
+ // // componentKey,
138
+ // // store: this,
139
+ // // otelContext,
140
+ // // })
141
+ // this.activeQueries.add(query)
142
+ // // TODO get rid of temporary query workaround
143
+ // if (this.temporaryQueries !== undefined) {
144
+ // this.temporaryQueries.add(query)
145
+ // }
146
+ // // NOTE we are not ending the span here but in the query `destroy` method
147
+ // return query
148
+ // })
149
+ // queryGraphQL = <TResult extends Record<string, any>, TVariableValues extends Record<string, any>>(
150
+ // document: DocumentNode<TResult, TVariableValues>,
151
+ // genVariableValues: TVariableValues | ((get: GetAtomResult) => TVariableValues),
152
+ // {
153
+ // componentKey,
154
+ // label,
155
+ // otelContext = otel.context.active(),
156
+ // }: {
157
+ // componentKey: ComponentKey
158
+ // label?: string
159
+ // otelContext?: otel.Context
160
+ // },
161
+ // ): LiveStoreGraphQLQuery<TResult, TVariableValues, TGraphQLContext> =>
162
+ // this.otel.tracer.startActiveSpan(
163
+ // `queryGraphQL:`, // NOTE span name will be overridden further down
164
+ // {},
165
+ // otelContext,
166
+ // (span) => {
167
+ // const otelContext = otel.trace.setSpan(otel.context.active(), span)
168
+ // if (this.graphQLContext === undefined) {
169
+ // return shouldNeverHappen("Can't run a GraphQL query on a store without GraphQL context")
170
+ // }
171
+ // const labelWithDefault = label ?? graphql.getOperationAST(document)?.name?.value ?? 'graphql'
172
+ // span.updateName(`queryGraphQL:${labelWithDefault}`)
173
+ // const variableValues$ = this.graph.makeThunk(
174
+ // (get) => {
175
+ // if (typeof genVariableValues === 'function') {
176
+ // return genVariableValues(makeGetAtomResult(get))
177
+ // } else {
178
+ // return genVariableValues
179
+ // }
180
+ // },
181
+ // { label: `${labelWithDefault}:variableValues`, meta: { liveStoreThunkType: 'graphqlVariableValues' } },
182
+ // // otelContext,
183
+ // )
184
+ // const resultsLabel = `${labelWithDefault}:results` + (this.temporaryQueries ? ':temp' : '')
185
+ // const results$ = this.graph.makeThunk<TResult>(
186
+ // (get, addDebugInfo) => {
187
+ // const variableValues = get(variableValues$)
188
+ // const { result, queriedTables } = this.queryGraphQLOnce(document, variableValues, otelContext)
189
+ // // Add dependencies on any tables that were used
190
+ // for (const tableName of queriedTables) {
191
+ // const tableRef = this.tableRefs[tableName]
192
+ // assertNever(tableRef !== undefined, `No table ref found for ${tableName}`)
193
+ // get(tableRef!)
194
+ // }
195
+ // addDebugInfo({ _tag: 'graphql', label: resultsLabel, query: graphql.print(document) })
196
+ // return result
197
+ // },
198
+ // { label: resultsLabel, meta: { liveStoreThunkType: 'graphqlResults' } },
199
+ // // otelContext,
200
+ // )
201
+ // const query = new LiveStoreGraphQLQuery({
202
+ // document,
203
+ // context: this.graphQLContext,
204
+ // results$,
205
+ // componentKey,
206
+ // label: labelWithDefault,
207
+ // store: this,
208
+ // otelContext,
209
+ // })
210
+ // this.activeQueries.add(query)
211
+ // // TODO get rid of temporary query workaround
212
+ // if (this.temporaryQueries !== undefined) {
213
+ // this.temporaryQueries.add(query)
214
+ // }
215
+ // // NOTE we are not ending the span here but in the query `destroy` method
216
+ // return query
217
+ // },
218
+ // )
219
+ // queryGraphQLOnce = <TResult extends Record<string, any>, TVariableValues extends Record<string, any>>(
220
+ // document: DocumentNode<TResult, TVariableValues>,
221
+ // variableValues: TVariableValues,
222
+ // otelContext: otel.Context = this.otel.queriesSpanContext,
223
+ // ): { result: TResult; queriedTables: string[] } => {
224
+ // const schema =
225
+ // this.graphQLSchema ?? shouldNeverHappen("Can't run a GraphQL query on a store without GraphQL schema")
226
+ // const context =
227
+ // this.graphQLContext ?? shouldNeverHappen("Can't run a GraphQL query on a store without GraphQL context")
228
+ // const tracer = this.otel.tracer
229
+ // const operationName = graphql.getOperationAST(document)?.name?.value
230
+ // return tracer.startActiveSpan(`executeGraphQLQuery: ${operationName}`, {}, otelContext, (span) => {
231
+ // try {
232
+ // span.setAttribute('graphql.variables', JSON.stringify(variableValues))
233
+ // span.setAttribute('graphql.query', graphql.print(document))
234
+ // context.queriedTables.clear()
235
+ // context.otelContext = otel.trace.setSpan(otel.context.active(), span)
236
+ // const res = graphql.executeSync({
237
+ // document,
238
+ // contextValue: context,
239
+ // schema: schema,
240
+ // variableValues,
241
+ // })
242
+ // // TODO track number of nested SQL queries via Otel + debug info
243
+ // if (res.errors) {
244
+ // span.setStatus({ code: otel.SpanStatusCode.ERROR, message: 'GraphQL error' })
245
+ // span.setAttribute('graphql.error', res.errors.join('\n'))
246
+ // span.setAttribute('graphql.error-detail', JSON.stringify(res.errors))
247
+ // console.error(`graphql error (${operationName})`, res.errors)
248
+ // }
249
+ // return { result: res.data as unknown as TResult, queriedTables: Array.from(context.queriedTables.values()) }
250
+ // } finally {
251
+ // span.end()
252
+ // }
253
+ // })
254
+ // }
168
255
  /**
169
256
  * Subscribe to the results of a query
170
257
  * Returns a function to cancel the subscription.
171
258
  */
172
- this.subscribe = (query, onNewValue, onSubsubscribe, options) => this.otel.tracer.startActiveSpan(`LiveStore.subscribe`, { attributes: { label: options?.label } }, query.otelContext, (span) => {
259
+ this.subscribe = (query, onNewValue, onSubsubscribe, options) => this.otel.tracer.startActiveSpan(`LiveStore.subscribe`, { attributes: { label: options?.label } }, options?.otelContext ?? this.otel.queriesSpanContext, (span) => {
173
260
  const otelContext = otel.trace.setSpan(otel.context.active(), span);
174
- const effect = this.graph.makeEffect((get) => {
175
- const result = get(query.results$);
176
- onNewValue(result);
177
- }, { label: `subscribe:${options?.label}` }, otelContext);
178
- const subscriptionKey = uuid();
261
+ const effect = this.graph.makeEffect((get) => onNewValue(get(query.results$)), {
262
+ label: `subscribe:${options?.label}`,
263
+ });
264
+ effect.doEffect(otelContext);
265
+ // const subscriptionKey = uuid()
179
266
  const unsubscribe = () => {
180
267
  try {
181
268
  this.graph.destroy(effect);
182
- query.activeSubscriptions.delete(subscriptionKey);
269
+ this.activeQueries.delete(query);
270
+ // query.activeSubscriptions.delete(subscriptionKey)
183
271
  onSubsubscribe?.();
184
272
  }
185
273
  finally {
186
274
  span.end();
187
275
  }
188
276
  };
189
- query.activeSubscriptions.set(subscriptionKey, unsubscribe);
277
+ this.activeQueries.add(query);
278
+ // query.activeSubscriptions.set(subscriptionKey, unsubscribe)
190
279
  return unsubscribe;
191
280
  });
192
- /**
193
- * Any queries created in the callback will be destroyed when the callback is complete.
194
- * Useful for temporarily creating reactive queries, which is an idempotent operation
195
- * that can be safely called inside a React useMemo hook.
196
- */
197
- this.inTempQueryContext = (callback) => {
198
- this.temporaryQueries = new Set();
199
- // TODO: consider errors / try/finally here?
200
- const result = callback();
201
- for (const query of this.temporaryQueries) {
202
- this.destroyQuery(query);
203
- }
204
- this.temporaryQueries = undefined;
205
- return result;
206
- };
207
281
  /**
208
282
  * Destroys the entire store, including all queries and subscriptions.
209
283
  *
210
284
  * Currently only used when shutting down the app for debugging purposes (e.g. to close Otel spans).
211
285
  */
212
286
  this.destroy = () => {
213
- for (const query of this.activeQueries) {
214
- this.destroyQuery(query);
215
- }
216
287
  Object.values(this.tableRefs).forEach((tableRef) => this.graph.destroy(tableRef));
217
- const applyEventsSpan = otel.trace.getSpan(this.otel.applyEventsSpanContext);
218
- applyEventsSpan.end();
219
- const queriesSpan = otel.trace.getSpan(this.otel.queriesSpanContext);
220
- queriesSpan.end();
288
+ otel.trace.getSpan(this.otel.applyEventsSpanContext).end();
289
+ otel.trace.getSpan(this.otel.queriesSpanContext).end();
221
290
  // TODO destroy active subscriptions
222
291
  };
223
- this.destroyQuery = (query) => {
224
- if (query._tag === 'sql') {
225
- // results are downstream of query string, so will automatically be destroyed together
226
- this.graph.destroy(query.queryString$);
227
- }
228
- else {
229
- this.graph.destroy(query.results$);
230
- }
231
- this.activeQueries.delete(query);
232
- query.destroy();
233
- };
234
- /**
235
- * Clean up queries and downstream subscriptions associated with a component.
236
- * This is critical to avoid memory leaks.
237
- */
238
- this.unmountComponent = (componentKey) => {
239
- for (const query of this.activeQueries) {
240
- if (query.componentKey === componentKey) {
241
- this.destroyQuery(query);
242
- }
243
- }
244
- };
245
292
  /* Apply a single write event to the store, and refresh all queries in response */
246
293
  this.applyEvent = (eventType, args = {}, options) => {
247
294
  const skipRefresh = options?.skipRefresh ?? false;
@@ -258,16 +305,23 @@ export class Store {
258
305
  assertNever(tableRef !== undefined, `No table ref found for ${tableName}`);
259
306
  tablesToUpdate.push([tableRef, null]);
260
307
  }
308
+ const debugRefreshReason = {
309
+ _tag: 'applyEvent',
310
+ event: { type: eventType, args },
311
+ writeTables: [...writeTables],
312
+ };
261
313
  // Update all table refs together in a batch, to only trigger one reactive update
262
- this.graph.setRefs(tablesToUpdate, {
263
- otelHint: 'applyEvents',
264
- skipRefresh,
265
- debugRefreshReason: {
266
- _tag: 'applyEvent',
267
- event: { type: eventType, args },
268
- writeTables: [...writeTables],
269
- },
270
- }, otelContext);
314
+ this.graph.setRefs(tablesToUpdate, { debugRefreshReason, otelContext });
315
+ if (skipRefresh === false) {
316
+ // TODO update the graph
317
+ // this.graph.refresh(
318
+ // {
319
+ // otelHint: 'applyEvents',
320
+ // debugRefreshReason,
321
+ // },
322
+ // otelContext,
323
+ // )
324
+ }
271
325
  }
272
326
  catch (e) {
273
327
  span.setStatus({ code: otel.SpanStatusCode.ERROR, message: e.toString() });
@@ -329,16 +383,17 @@ export class Store {
329
383
  assertNever(tableRef !== undefined, `No table ref found for ${tableName}`);
330
384
  tablesToUpdate.push([tableRef, null]);
331
385
  }
386
+ const debugRefreshReason = {
387
+ _tag: 'applyEvents',
388
+ events: [...events].map((e) => ({ type: e.eventType, args: e.args })),
389
+ writeTables: [...writeTables],
390
+ };
332
391
  // Update all table refs together in a batch, to only trigger one reactive update
333
- this.graph.setRefs(tablesToUpdate, {
334
- otelHint: 'applyEvents',
335
- skipRefresh,
336
- debugRefreshReason: {
337
- _tag: 'applyEvents',
338
- events: [...events].map((e) => ({ type: e.eventType, args: e.args })),
339
- writeTables: [...writeTables],
340
- },
341
- }, otelContext);
392
+ this.graph.setRefs(tablesToUpdate, { debugRefreshReason, otelContext });
393
+ if (skipRefresh === false) {
394
+ // TODO update the graph
395
+ // this.graph.refresh({ debugRefreshReason, otelHint: 'applyEvents' }, otelContext)
396
+ }
342
397
  }
343
398
  catch (e) {
344
399
  span.setStatus({ code: otel.SpanStatusCode.ERROR, message: e.toString() });
@@ -356,8 +411,9 @@ export class Store {
356
411
  this.manualRefresh = (options) => {
357
412
  const { label } = options ?? {};
358
413
  this.otel.tracer.startActiveSpan('LiveStore:manualRefresh', { attributes: { 'livestore.manualRefreshLabel': label } }, this.otel.applyEventsSpanContext, (span) => {
359
- const otelContext = otel.trace.setSpan(otel.context.active(), span);
360
- this.graph.refresh({ otelHint: 'manualRefresh', debugRefreshReason: { _tag: 'manualRefresh' } }, otelContext);
414
+ // const otelContext = otel.trace.setSpan(otel.context.active(), span)
415
+ // TODO update the graph
416
+ // this.graph.refresh({ otelHint: 'manualRefresh', debugRefreshReason: { _tag: 'manualRefresh' } }, otelContext)
361
417
  span.end();
362
418
  });
363
419
  };
@@ -404,13 +460,13 @@ export class Store {
404
460
  // Synchronously apply the event to the in-memory database
405
461
  // const { durationMs } = this.inMemoryDB.applyEvent(eventWithId, actionDefinition, otelContext)
406
462
  const { statement, bindValues } = eventToSql(eventWithId, actionDefinition);
407
- const { durationMs } = this.inMemoryDB.execute(statement.sql, bindValues, statement.writeTables, {
463
+ const { durationMs } = this.inMemoryDB.execute(statement.sql, prepareBindValues(bindValues, statement.sql), statement.writeTables, {
408
464
  otelContext,
409
465
  });
410
466
  // Asynchronously apply the event to a persistent storage (we're not awaiting this promise here)
411
467
  if (this.storage !== undefined) {
412
468
  // this.storage.applyEvent(eventWithId, actionDefinition, span)
413
- this.storage.execute(statement.sql, bindValues, span);
469
+ this.storage.execute(statement.sql, prepareBindValues(bindValues, statement.sql), span);
414
470
  }
415
471
  // Uncomment to print a list of queries currently registered on the store
416
472
  // console.log(JSON.parse(JSON.stringify([...this.queries].map((q) => `${labelForKey(q.componentKey)}/${q.label}`))))
@@ -427,20 +483,21 @@ export class Store {
427
483
  * This should only be used for framework-internal purposes;
428
484
  * all app writes should go through applyEvent.
429
485
  */
430
- this.execute = async (query, params = {}, writeTables) => {
431
- this.inMemoryDB.execute(query, params, writeTables);
486
+ this.execute = (query, params = {}, writeTables) => {
487
+ this.inMemoryDB.execute(query, prepareBindValues(params, query), writeTables);
432
488
  if (this.storage !== undefined) {
433
489
  const parentSpan = otel.trace.getSpan(otel.context.active());
434
- this.storage.execute(query, params, parentSpan);
490
+ this.storage.execute(query, prepareBindValues(params, query), parentSpan);
435
491
  }
436
492
  };
437
493
  this.inMemoryDB = db;
438
- this.graph = new ReactiveGraph({
439
- // TODO move this into React module
440
- // Do all our updates inside a single React setState batch to avoid multiple UI re-renders
441
- effectsWrapper: (run) => ReactDOM.unstable_batchedUpdates(() => run()),
442
- otelTracer,
443
- });
494
+ this._proxyDb = dbProxy;
495
+ // this.graph = new ReactiveGraph({
496
+ // // TODO move this into React module
497
+ // // Do all our updates inside a single React setState batch to avoid multiple UI re-renders
498
+ // effectsWrapper: (run) => ReactDOM.unstable_batchedUpdates(() => run()),
499
+ // otelTracer,
500
+ // })
444
501
  this.schema = schema;
445
502
  // TODO generalize the `tableRefs` concept to allow finer-grained refs
446
503
  this.tableRefs = {};
@@ -450,6 +507,8 @@ export class Store {
450
507
  const otelApplyEventsSpanContext = otel.trace.setSpan(otel.context.active(), applyEventsSpan);
451
508
  const queriesSpan = otelTracer.startSpan('LiveStore:queries', {}, otelRootSpanContext);
452
509
  const otelQueriesSpanContext = otel.trace.setSpan(otel.context.active(), queriesSpan);
510
+ this.graph = dbGraph;
511
+ this.graph.context = { store: this, otelTracer, rootOtelContext: otelQueriesSpanContext };
453
512
  this.otel = {
454
513
  tracer: otelTracer,
455
514
  applyEventsSpanContext: otelApplyEventsSpanContext,
@@ -485,40 +544,29 @@ Store.createStore = (storeOptions, parentSpan) => {
485
544
  });
486
545
  };
487
546
  /** Create a new LiveStore Store */
488
- export const createStore = async ({ schema, loadStorage, graphQLOptions, otelTracer = makeNoopTracer(), otelRootSpanContext = otel.context.active(), boot, }) => {
547
+ export const createStore = async ({ schema, loadStorage, graphQLOptions, otelTracer = makeNoopTracer(), otelRootSpanContext = otel.context.active(), boot, sqlite3, }) => {
489
548
  return otelTracer.startActiveSpan('createStore', {}, otelRootSpanContext, async (span) => {
490
549
  try {
491
550
  const otelContext = otel.trace.setSpan(otel.context.active(), span);
492
- const loadStorageAndPersistedData = async () => {
493
- const storage = await otelTracer.startActiveSpan('storage:load', {}, otelContext, async (span) => {
494
- try {
495
- const init = await loadStorage();
496
- const parentSpan = otel.trace.getSpan(otel.context.active()) ?? makeNoopSpan();
497
- return init({ otelTracer, parentSpan });
498
- }
499
- finally {
500
- span.end();
501
- }
502
- });
503
- const persistedData = await otelTracer.startActiveSpan('storage:getPersistedData', {}, otelContext, async (span) => {
504
- try {
505
- return await storage.getPersistedData(span);
506
- }
507
- finally {
508
- span.end();
509
- }
510
- });
511
- return { storage, persistedData };
512
- };
513
- const loadSqlite3 = () => initSqlite3Wasm({
514
- // Required to load the wasm binary asynchronously. Of course, you can host it wherever you want
515
- // You can omit locateFile completely when running in node
516
- // locateFile: () => `/sql-wasm.wasm`,
517
- print: (message) => console.log(`[livestore sqlite] ${message}`),
518
- printErr: (message) => console.error(`[livestore sqlite] ${message}`),
551
+ const storage = await otelTracer.startActiveSpan('storage:load', {}, otelContext, async (span) => {
552
+ try {
553
+ const init = await loadStorage();
554
+ const parentSpan = otel.trace.getSpan(otel.context.active()) ?? makeNoopSpan();
555
+ return init({ otelTracer, parentSpan });
556
+ }
557
+ finally {
558
+ span.end();
559
+ }
519
560
  });
520
- const [{ storage, persistedData }, sqlite3] = await Promise.all([loadStorageAndPersistedData(), loadSqlite3()]);
521
- const db = InMemoryDatabase.load(persistedData, otelTracer, otelRootSpanContext, sqlite3);
561
+ const persistedData = await otelTracer.startActiveSpan('storage:getPersistedData', {}, otelContext, async (span) => {
562
+ try {
563
+ return await storage.getPersistedData(span);
564
+ }
565
+ finally {
566
+ span.end();
567
+ }
568
+ });
569
+ const db = InMemoryDatabase.load({ data: persistedData, otelTracer, otelRootSpanContext, sqlite3 });
522
570
  // Proxy to `db` that also mirrors `execute` calls to `storage`
523
571
  const dbProxy = new Proxy(db, {
524
572
  get: (db, prop, receiver) => {
@@ -529,6 +577,15 @@ export const createStore = async ({ schema, loadStorage, graphQLOptions, otelTra
529
577
  };
530
578
  return execute;
531
579
  }
580
+ else if (prop === 'select') {
581
+ // NOTE we're even proxying `select` calls here as some apps (e.g. Overtone) currently rely on this
582
+ // TODO remove this once we've migrated all apps to use `execute` instead of `select`
583
+ const select = (query, options = {}) => {
584
+ storage.execute(query, options.bindValues);
585
+ return db.select(query, options);
586
+ };
587
+ return select;
588
+ }
532
589
  else {
533
590
  return Reflect.get(db, prop, receiver);
534
591
  }
@@ -553,7 +610,7 @@ export const createStore = async ({ schema, loadStorage, graphQLOptions, otelTra
553
610
  // TODO: we can't apply the schema at this point, we've already loaded persisted data!
554
611
  // Think about what to do about this case.
555
612
  // await applySchema(db, schema)
556
- return Store.createStore({ db, schema, storage, graphQLOptions, otelTracer, otelRootSpanContext }, span);
613
+ return Store.createStore({ db, dbProxy, schema, storage, graphQLOptions, otelTracer, otelRootSpanContext }, span);
557
614
  }
558
615
  finally {
559
616
  span.end();