@livestore/livestore 0.0.10 → 0.0.13

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 (151) hide show
  1. package/README.md +7 -7
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/__tests__/react/fixture.d.ts +4 -120
  4. package/dist/__tests__/react/fixture.d.ts.map +1 -1
  5. package/dist/__tests__/react/fixture.js +19 -26
  6. package/dist/__tests__/react/fixture.js.map +1 -1
  7. package/dist/__tests__/reactive.test.js +31 -0
  8. package/dist/__tests__/reactive.test.js.map +1 -1
  9. package/dist/backends/base.d.ts +4 -4
  10. package/dist/backends/{web-in-memory.d.ts → in-memory/index.d.ts} +6 -6
  11. package/dist/backends/in-memory/index.d.ts.map +1 -0
  12. package/dist/backends/{web-in-memory.js → in-memory/index.js} +7 -7
  13. package/dist/backends/in-memory/index.js.map +1 -0
  14. package/dist/backends/index.d.ts +4 -8
  15. package/dist/backends/index.d.ts.map +1 -1
  16. package/dist/backends/index.js +0 -22
  17. package/dist/backends/index.js.map +1 -1
  18. package/dist/backends/{tauri.d.ts → tauri/index.d.ts} +5 -6
  19. package/dist/backends/tauri/index.d.ts.map +1 -0
  20. package/dist/backends/{tauri.js → tauri/index.js} +4 -4
  21. package/dist/backends/tauri/index.js.map +1 -0
  22. package/dist/backends/{web.d.ts → web-worker/index.d.ts} +6 -7
  23. package/dist/backends/web-worker/index.d.ts.map +1 -0
  24. package/dist/backends/{web.js → web-worker/index.js} +6 -6
  25. package/dist/backends/web-worker/index.js.map +1 -0
  26. package/dist/backends/{web-worker.d.ts → web-worker/worker.d.ts} +3 -3
  27. package/dist/backends/web-worker/worker.d.ts.map +1 -0
  28. package/dist/backends/{web-worker.js → web-worker/worker.js} +3 -3
  29. package/dist/backends/web-worker/worker.js.map +1 -0
  30. package/dist/effect/LiveStore.d.ts +6 -6
  31. package/dist/effect/LiveStore.d.ts.map +1 -1
  32. package/dist/effect/LiveStore.js +2 -5
  33. package/dist/effect/LiveStore.js.map +1 -1
  34. package/dist/events.d.ts +1 -1
  35. package/dist/events.d.ts.map +1 -1
  36. package/dist/events.js +1 -1
  37. package/dist/events.js.map +1 -1
  38. package/dist/inMemoryDatabase.d.ts +5 -10
  39. package/dist/inMemoryDatabase.d.ts.map +1 -1
  40. package/dist/inMemoryDatabase.js +78 -89
  41. package/dist/inMemoryDatabase.js.map +1 -1
  42. package/dist/index.d.ts +7 -7
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +3 -4
  45. package/dist/index.js.map +1 -1
  46. package/dist/migrations.d.ts +9 -0
  47. package/dist/migrations.d.ts.map +1 -0
  48. package/dist/migrations.js +62 -0
  49. package/dist/migrations.js.map +1 -0
  50. package/dist/otel.d.ts +0 -1
  51. package/dist/otel.d.ts.map +1 -1
  52. package/dist/otel.js +0 -11
  53. package/dist/otel.js.map +1 -1
  54. package/dist/react/LiveStoreProvider.d.ts +5 -4
  55. package/dist/react/LiveStoreProvider.d.ts.map +1 -1
  56. package/dist/react/LiveStoreProvider.js +6 -5
  57. package/dist/react/LiveStoreProvider.js.map +1 -1
  58. package/dist/react/index.d.ts +2 -1
  59. package/dist/react/index.d.ts.map +1 -1
  60. package/dist/react/index.js.map +1 -1
  61. package/dist/react/useGlobalQuery.d.ts.map +1 -1
  62. package/dist/react/useGlobalQuery.js +0 -2
  63. package/dist/react/useGlobalQuery.js.map +1 -1
  64. package/dist/react/useLiveStoreComponent.d.ts +22 -17
  65. package/dist/react/useLiveStoreComponent.d.ts.map +1 -1
  66. package/dist/react/useLiveStoreComponent.js +46 -17
  67. package/dist/react/useLiveStoreComponent.js.map +1 -1
  68. package/dist/reactive.d.ts.map +1 -1
  69. package/dist/reactive.js +1 -0
  70. package/dist/reactive.js.map +1 -1
  71. package/dist/schema.d.ts +32 -112
  72. package/dist/schema.d.ts.map +1 -1
  73. package/dist/schema.js +36 -79
  74. package/dist/schema.js.map +1 -1
  75. package/dist/storage/base.d.ts +10 -0
  76. package/dist/storage/base.d.ts.map +1 -0
  77. package/dist/storage/base.js +14 -0
  78. package/dist/storage/base.js.map +1 -0
  79. package/dist/storage/in-memory/index.d.ts +15 -0
  80. package/dist/storage/in-memory/index.d.ts.map +1 -0
  81. package/dist/storage/in-memory/index.js +14 -0
  82. package/dist/storage/in-memory/index.js.map +1 -0
  83. package/dist/storage/index.d.ts +14 -0
  84. package/dist/storage/index.d.ts.map +1 -0
  85. package/dist/storage/index.js +9 -0
  86. package/dist/storage/index.js.map +1 -0
  87. package/dist/storage/tauri/index.d.ts +19 -0
  88. package/dist/storage/tauri/index.d.ts.map +1 -0
  89. package/dist/storage/tauri/index.js +38 -0
  90. package/dist/storage/tauri/index.js.map +1 -0
  91. package/dist/storage/utils/idb.d.ts +10 -0
  92. package/dist/storage/utils/idb.d.ts.map +1 -0
  93. package/dist/storage/utils/idb.js +58 -0
  94. package/dist/storage/utils/idb.js.map +1 -0
  95. package/dist/storage/web-worker/index.d.ts +27 -0
  96. package/dist/storage/web-worker/index.d.ts.map +1 -0
  97. package/dist/storage/web-worker/index.js +76 -0
  98. package/dist/storage/web-worker/index.js.map +1 -0
  99. package/dist/storage/web-worker/worker.d.ts +13 -0
  100. package/dist/storage/web-worker/worker.d.ts.map +1 -0
  101. package/dist/storage/web-worker/worker.js +110 -0
  102. package/dist/storage/web-worker/worker.js.map +1 -0
  103. package/dist/store.d.ts +6 -6
  104. package/dist/store.d.ts.map +1 -1
  105. package/dist/store.js +93 -63
  106. package/dist/store.js.map +1 -1
  107. package/dist/util.d.ts +3 -1
  108. package/dist/util.d.ts.map +1 -1
  109. package/dist/util.js +2 -0
  110. package/dist/util.js.map +1 -1
  111. package/package.json +50 -23
  112. package/src/__tests__/react/fixture.tsx +19 -28
  113. package/src/__tests__/reactive.test.ts +39 -0
  114. package/src/effect/LiveStore.ts +8 -13
  115. package/src/events.ts +1 -1
  116. package/src/inMemoryDatabase.ts +100 -117
  117. package/src/index.ts +10 -16
  118. package/src/migrations.ts +101 -0
  119. package/src/otel.ts +0 -11
  120. package/src/react/LiveStoreProvider.tsx +12 -8
  121. package/src/react/index.ts +9 -0
  122. package/src/react/useGlobalQuery.ts +0 -3
  123. package/src/react/useLiveStoreComponent.ts +98 -38
  124. package/src/reactive.ts +2 -1
  125. package/src/schema.ts +72 -145
  126. package/src/storage/in-memory/index.ts +21 -0
  127. package/src/storage/index.ts +27 -0
  128. package/src/{backends/tauri.ts → storage/tauri/index.ts} +13 -27
  129. package/src/storage/web-worker/index.ts +118 -0
  130. package/src/{backends/web-worker.ts → storage/web-worker/worker.ts} +17 -52
  131. package/src/store.ts +112 -79
  132. package/src/util.ts +5 -1
  133. package/tsconfig.json +1 -3
  134. package/dist/backends/noop.d.ts +0 -18
  135. package/dist/backends/noop.d.ts.map +0 -1
  136. package/dist/backends/noop.js +0 -21
  137. package/dist/backends/noop.js.map +0 -1
  138. package/dist/backends/tauri.d.ts.map +0 -1
  139. package/dist/backends/tauri.js.map +0 -1
  140. package/dist/backends/web-in-memory.d.ts.map +0 -1
  141. package/dist/backends/web-in-memory.js.map +0 -1
  142. package/dist/backends/web-worker.d.ts.map +0 -1
  143. package/dist/backends/web-worker.js.map +0 -1
  144. package/dist/backends/web.d.ts.map +0 -1
  145. package/dist/backends/web.js.map +0 -1
  146. package/src/backends/base.ts +0 -67
  147. package/src/backends/index.ts +0 -98
  148. package/src/backends/noop.ts +0 -32
  149. package/src/backends/web-in-memory.ts +0 -65
  150. package/src/backends/web.ts +0 -97
  151. /package/src/{backends → storage}/utils/idb.ts +0 -0
@@ -0,0 +1,10 @@
1
+ export declare class IDB {
2
+ private dbName;
3
+ private storeName;
4
+ private db;
5
+ constructor(dbName: string, storeName?: string);
6
+ private open;
7
+ get(key: string): Promise<Uint8Array | undefined>;
8
+ put(key: string, value: Uint8Array): Promise<void>;
9
+ }
10
+ //# sourceMappingURL=idb.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idb.d.ts","sourceRoot":"","sources":["../../../src/storage/utils/idb.ts"],"names":[],"mappings":"AAGA,qBAAa,GAAG;IAIZ,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,SAAS;IAJnB,OAAO,CAAC,EAAE,CAA2B;gBAG3B,MAAM,EAAE,MAAM,EACd,SAAS,GAAE,MAAuB;YAG9B,IAAI;IAwBL,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAkBjD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CAiBhE"}
@@ -0,0 +1,58 @@
1
+ /* eslint-disable unicorn/prefer-add-event-listener */
2
+ /* eslint-disable prefer-arrow/prefer-arrow-functions */
3
+ export class IDB {
4
+ constructor(dbName, storeName = 'binary_store') {
5
+ this.dbName = dbName;
6
+ this.storeName = storeName;
7
+ this.db = null;
8
+ }
9
+ async open() {
10
+ if (this.db)
11
+ return this.db;
12
+ return new Promise((resolve, reject) => {
13
+ const openRequest = indexedDB.open(this.dbName, 1);
14
+ openRequest.onupgradeneeded = () => {
15
+ const db = openRequest.result;
16
+ if (!db.objectStoreNames.contains(this.storeName)) {
17
+ db.createObjectStore(this.storeName);
18
+ }
19
+ };
20
+ openRequest.onsuccess = () => {
21
+ this.db = openRequest.result;
22
+ resolve(this.db);
23
+ };
24
+ openRequest.onerror = () => {
25
+ reject(new Error('Failed to open database.'));
26
+ };
27
+ });
28
+ }
29
+ async get(key) {
30
+ const db = await this.open();
31
+ return new Promise((resolve, reject) => {
32
+ const transaction = db.transaction(this.storeName, 'readonly');
33
+ const store = transaction.objectStore(this.storeName);
34
+ const getRequest = store.get(key);
35
+ getRequest.onsuccess = () => {
36
+ resolve(getRequest.result);
37
+ };
38
+ getRequest.onerror = () => {
39
+ reject(new Error('Failed to get data.'));
40
+ };
41
+ });
42
+ }
43
+ async put(key, value) {
44
+ const db = await this.open();
45
+ return new Promise((resolve, reject) => {
46
+ const transaction = db.transaction(this.storeName, 'readwrite');
47
+ const store = transaction.objectStore(this.storeName);
48
+ const putRequest = store.put(value, key);
49
+ putRequest.onsuccess = () => {
50
+ resolve();
51
+ };
52
+ putRequest.onerror = () => {
53
+ reject(new Error('Failed to write data.'));
54
+ };
55
+ });
56
+ }
57
+ }
58
+ //# sourceMappingURL=idb.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idb.js","sourceRoot":"","sources":["../../../src/storage/utils/idb.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type * as otel from '@opentelemetry/api';
2
+ import * as Comlink from 'comlink';
3
+ import type { ParamsObject } from '../../util.js';
4
+ import type { Storage, StorageOtelProps } from '../index.js';
5
+ import type { WrappedWorker } from './worker.js';
6
+ export type StorageType = 'opfs' | 'indexeddb';
7
+ export type StorageOptionsWeb = {
8
+ /** Specifies where to persist data for this storage */
9
+ type: StorageType;
10
+ virtualFilename: string;
11
+ };
12
+ export declare class WebWorkerStorage implements Storage {
13
+ worker: Comlink.Remote<WrappedWorker>;
14
+ options: StorageOptionsWeb;
15
+ otelTracer: otel.Tracer;
16
+ executionBacklog: {
17
+ query: string;
18
+ bindValues?: ParamsObject;
19
+ }[];
20
+ executionPromise: Promise<void> | undefined;
21
+ private constructor();
22
+ static load: (options: StorageOptionsWeb) => ({ otelTracer }: StorageOtelProps) => WebWorkerStorage;
23
+ execute: (query: string, bindValues_?: ParamsObject) => void;
24
+ private executeBacklog;
25
+ getPersistedData: (_parentSpan?: otel.Span) => Promise<Uint8Array>;
26
+ }
27
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/storage/web-worker/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,IAAI,MAAM,oBAAoB,CAAA;AAC/C,OAAO,KAAK,OAAO,MAAM,SAAS,CAAA;AAElC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAEjD,OAAO,KAAK,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAE5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhD,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,WAAW,CAAA;AAE9C,MAAM,MAAM,iBAAiB,GAAG;IAC9B,uDAAuD;IACvD,IAAI,EAAE,WAAW,CAAA;IACjB,eAAe,EAAE,MAAM,CAAA;CACxB,CAAA;AAED,qBAAa,gBAAiB,YAAW,OAAO;IAC9C,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAA;IACrC,OAAO,EAAE,iBAAiB,CAAA;IAC1B,UAAU,EAAE,IAAI,CAAC,MAAM,CAAA;IAEvB,gBAAgB,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,YAAY,CAAA;KAAE,EAAE,CAAK;IACrE,gBAAgB,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,SAAS,CAAA;IAE3C,OAAO;IAmBP,MAAM,CAAC,IAAI,YAAa,iBAAiB,sBASf,gBAAgB,sBAOzC;IAED,OAAO,UAAW,MAAM,gBAAgB,YAAY,UAcnD;IAED,OAAO,CAAC,cAAc,CAIrB;IAED,gBAAgB,iBAAwB,KAAK,IAAI,KAAG,QAAQ,UAAU,CAAC,CAAkC;CAC1G"}
@@ -0,0 +1,76 @@
1
+ import { casesHandled } from '@livestore/utils';
2
+ import * as Comlink from 'comlink';
3
+ import { prepareBindValues } from '../../util.js';
4
+ import { IDB } from '../utils/idb.js';
5
+ export class WebWorkerStorage {
6
+ constructor({ worker, options, otelTracer, executionPromise, }) {
7
+ this.executionBacklog = [];
8
+ this.execute = (query, bindValues_) => {
9
+ const bindValues = prepareBindValues(bindValues_ ?? {}, query);
10
+ this.executionBacklog.push({ query, bindValues });
11
+ // Instead of sending the queries to the worker immediately, we wait a bit and batch them up (which reduces the number of messages sent to the worker)
12
+ if (this.executionPromise === undefined) {
13
+ this.executionPromise = new Promise((resolve) => {
14
+ setTimeout(() => {
15
+ this.executeBacklog();
16
+ resolve();
17
+ }, 10);
18
+ });
19
+ }
20
+ };
21
+ this.executeBacklog = () => {
22
+ void this.worker.executeBulk(this.executionBacklog);
23
+ this.executionBacklog = [];
24
+ this.executionPromise = undefined;
25
+ };
26
+ this.getPersistedData = async (_parentSpan) => getPersistedData(this.options);
27
+ this.worker = worker;
28
+ this.options = options;
29
+ this.otelTracer = otelTracer;
30
+ this.executionPromise = executionPromise;
31
+ executionPromise.then(() => this.executeBacklog());
32
+ }
33
+ }
34
+ WebWorkerStorage.load = (options) => {
35
+ // TODO: Importing the worker like this only works with Vite;
36
+ // should this really be inside the LiveStore library?
37
+ // Doesn't work with Firefox right now during dev https://bugzilla.mozilla.org/show_bug.cgi?id=1247687
38
+ const worker = new Worker(new URL('./worker.js', import.meta.url), {
39
+ type: 'module',
40
+ });
41
+ const wrappedWorker = Comlink.wrap(worker);
42
+ return ({ otelTracer }) => new WebWorkerStorage({
43
+ worker: wrappedWorker,
44
+ options,
45
+ otelTracer,
46
+ executionPromise: wrappedWorker.initialize(options),
47
+ });
48
+ };
49
+ const getPersistedData = async (options) => {
50
+ switch (options.type) {
51
+ case 'opfs': {
52
+ try {
53
+ const rootHandle = await navigator.storage.getDirectory();
54
+ const fileHandle = await rootHandle.getFileHandle(options.virtualFilename + '.db');
55
+ const file = await fileHandle.getFile();
56
+ const buffer = await file.arrayBuffer();
57
+ const data = new Uint8Array(buffer);
58
+ return data;
59
+ }
60
+ catch (error) {
61
+ if (error instanceof DOMException && error.name === 'NotFoundError') {
62
+ return new Uint8Array();
63
+ }
64
+ throw error;
65
+ }
66
+ }
67
+ case 'indexeddb': {
68
+ const idb = new IDB(options.virtualFilename);
69
+ return (await idb.get('db')) ?? new Uint8Array();
70
+ }
71
+ default: {
72
+ casesHandled(options.type);
73
+ }
74
+ }
75
+ };
76
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/storage/web-worker/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { Bindable } from '../../util.js';
2
+ import type { StorageOptionsWeb } from './index.js';
3
+ type ExecutionQueueItem = {
4
+ query: string;
5
+ bindValues?: Bindable;
6
+ };
7
+ declare const wrappedWorker: {
8
+ initialize: (options: StorageOptionsWeb) => Promise<void>;
9
+ executeBulk: (executionItems: ExecutionQueueItem[]) => void;
10
+ };
11
+ export type WrappedWorker = typeof wrappedWorker;
12
+ export {};
13
+ //# sourceMappingURL=worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../../src/storage/web-worker/worker.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAG7C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAsEnD,KAAK,kBAAkB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,QAAQ,CAAA;CAAE,CAAA;AA8ClE,QAAA,MAAM,aAAa;0BA5FgB,iBAAiB;kCAgDf,kBAAkB,EAAE,KAAG,IAAI;CA4Cf,CAAA;AAEjD,MAAM,MAAM,aAAa,GAAG,OAAO,aAAa,CAAA"}
@@ -0,0 +1,110 @@
1
+ // Web Worker file for running SQLite in a web worker.
2
+ // TODO: create types for these libraries? SQL.js already should have types;
3
+ // we just need the types to apply to the fork.
4
+ import { shouldNeverHappen } from '@livestore/utils';
5
+ import * as Comlink from 'comlink';
6
+ import sqlite3InitModule from 'sqlite-esm';
7
+ import { casesHandled, sql } from '../../util.js';
8
+ import { IDB } from '../utils/idb.js';
9
+ // A global variable to hold the database connection.
10
+ // let db: SqliteWasm.Database
11
+ let db;
12
+ let sqlite3;
13
+ // TODO get rid of this in favour of a "proper" IDB SQLite storage
14
+ let idb;
15
+ /** The location where this database storage persists its data */
16
+ let options_;
17
+ const configureConnection = () => db.exec(sql `
18
+ PRAGMA page_size=8192;
19
+ PRAGMA journal_mode=MEMORY;
20
+ PRAGMA foreign_keys='ON'; -- we want foreign key constraints to be enforced
21
+ `);
22
+ /** A full virtual filename in the IDB FS */
23
+ const fullyQualifiedFilename = (name) => `${name}.db`;
24
+ const initialize = async (options) => {
25
+ options_ = options;
26
+ sqlite3 = await sqlite3InitModule({
27
+ print: (message) => console.log(`[sql-client] ${message}`),
28
+ printErr: (message) => console.error(`[sql-client] ${message}`),
29
+ });
30
+ switch (options.type) {
31
+ case 'opfs': {
32
+ try {
33
+ db = new sqlite3.oo1.OpfsDb(fullyQualifiedFilename(options.virtualFilename)); // , 'c'
34
+ }
35
+ catch (e) {
36
+ debugger;
37
+ }
38
+ break;
39
+ }
40
+ case 'indexeddb': {
41
+ try {
42
+ db = new sqlite3.oo1.DB({ filename: ':memory:', flags: 'c' });
43
+ idb = new IDB(options.virtualFilename);
44
+ const bytes = await idb.get('db');
45
+ if (bytes !== undefined) {
46
+ // Based on https://sqlite.org/forum/forumpost/2119230da8ac5357a13b731f462dc76e08621a4a29724f7906d5f35bb8508465
47
+ // TODO find cleaner way to do this once possible in sqlite3-wasm
48
+ const p = sqlite3.wasm.allocFromTypedArray(bytes);
49
+ const _rc = sqlite3.capi.sqlite3_deserialize(db.pointer, 'main', p, bytes.length, bytes.length, 0);
50
+ }
51
+ }
52
+ catch (e) {
53
+ debugger;
54
+ }
55
+ break;
56
+ }
57
+ default: {
58
+ casesHandled(options.type);
59
+ }
60
+ }
61
+ configureConnection();
62
+ };
63
+ // TODO get rid of this in favour of a "proper" IDB SQLite storage
64
+ let idbPersistTimeout;
65
+ const executeBulk = (executionItems) => {
66
+ let batchItems = [];
67
+ while (executionItems.length > 0) {
68
+ try {
69
+ db.exec('BEGIN TRANSACTION'); // Start the transaction
70
+ batchItems = executionItems.splice(0, 50);
71
+ for (const { query, bindValues } of batchItems) {
72
+ db.exec({
73
+ sql: query,
74
+ bind: bindValues,
75
+ returnValue: 'resultRows',
76
+ rowMode: 'object',
77
+ });
78
+ }
79
+ db.exec('COMMIT'); // Commit the transaction
80
+ }
81
+ catch (error) {
82
+ try {
83
+ db.exec('ROLLBACK'); // Rollback in case of an error
84
+ }
85
+ catch (e) {
86
+ console.error('Error rolling back transaction', e);
87
+ }
88
+ shouldNeverHappen(`Error executing query: ${error} \n ${JSON.stringify(batchItems)}`);
89
+ }
90
+ }
91
+ // TODO get rid of this in favour of a "proper" IDB SQLite storage
92
+ if (options_.type === 'indexeddb') {
93
+ if (idbPersistTimeout !== undefined) {
94
+ clearTimeout(idbPersistTimeout);
95
+ }
96
+ idbPersistTimeout = setTimeout(() => {
97
+ const data = sqlite3.capi.sqlite3_js_db_export(db.pointer);
98
+ void idb.put('db', data);
99
+ }, 1000);
100
+ }
101
+ };
102
+ const wrappedWorker = { initialize, executeBulk };
103
+ Comlink.expose(wrappedWorker);
104
+ // NOTE keep this around for debugging
105
+ // db.exec({
106
+ // sql: `select * from sqlite_master where name = 'library_tracks'`,
107
+ // callback: (_: TODO) => console.log(_),
108
+ // rowMode: 'object',
109
+ // } as TODO)
110
+ //# sourceMappingURL=worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.js","sourceRoot":"","sources":["../../../src/storage/web-worker/worker.ts"],"names":[],"mappings":"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"}
package/dist/store.d.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
2
2
  import * as otel from '@opentelemetry/api';
3
3
  import type { GraphQLSchema } from 'graphql';
4
- import type { Backend, BackendOptions } from './backends/index.js';
5
4
  import type { ComponentKey } from './componentKey.js';
6
5
  import type { LiveStoreEvent } from './events.js';
7
6
  import { InMemoryDatabase } from './inMemoryDatabase.js';
@@ -11,6 +10,7 @@ import { LiveStoreGraphQLQuery } from './reactiveQueries/graphql.js';
11
10
  import { LiveStoreJSQuery } from './reactiveQueries/js.js';
12
11
  import { LiveStoreSQLQuery } from './reactiveQueries/sql.js';
13
12
  import type { GetActionArgs, Schema } from './schema.js';
13
+ import type { Storage, StorageInit } from './storage/index.js';
14
14
  import type { Bindable, ParamsObject } from './util.js';
15
15
  export type LiveStoreQuery<TResult extends Record<string, any> = any> = LiveStoreSQLQuery<TResult> | LiveStoreJSQuery<TResult> | LiveStoreGraphQLQuery<TResult, any, any>;
16
16
  export type BaseGraphQLContext = {
@@ -27,7 +27,7 @@ export type GraphQLOptions<TContext> = {
27
27
  export type StoreOptions<TGraphQLContext extends BaseGraphQLContext> = {
28
28
  db: InMemoryDatabase;
29
29
  schema: Schema;
30
- backend?: Backend;
30
+ storage?: Storage;
31
31
  graphQLOptions?: GraphQLOptions<TGraphQLContext>;
32
32
  otelTracer: otel.Tracer;
33
33
  otelRootSpanContext: otel.Context;
@@ -79,7 +79,7 @@ export declare class Store<TGraphQLContext extends BaseGraphQLContext> {
79
79
  [key: string]: Ref<null>;
80
80
  };
81
81
  activeQueries: Set<LiveStoreQuery>;
82
- backend?: Backend;
82
+ storage?: Storage;
83
83
  temporaryQueries: Set<LiveStoreQuery> | undefined;
84
84
  private constructor();
85
85
  static createStore: <TGraphQLContext_1 extends BaseGraphQLContext>(storeOptions: StoreOptions<TGraphQLContext_1>, parentSpan: otel.Span) => Store<TGraphQLContext_1>;
@@ -181,12 +181,12 @@ export declare class Store<TGraphQLContext extends BaseGraphQLContext> {
181
181
  execute: (query: string, params?: ParamsObject, writeTables?: string[]) => Promise<void>;
182
182
  }
183
183
  /** Create a new LiveStore Store */
184
- export declare const createStore: <TGraphQLContext extends BaseGraphQLContext>({ schema, backendOptions, graphQLOptions, otelTracer, otelRootSpanContext, boot, }: {
184
+ export declare const createStore: <TGraphQLContext extends BaseGraphQLContext>({ schema, loadStorage, graphQLOptions, otelTracer, otelRootSpanContext, boot, }: {
185
185
  schema: Schema;
186
- backendOptions: BackendOptions;
186
+ loadStorage: () => StorageInit | Promise<StorageInit>;
187
187
  graphQLOptions?: GraphQLOptions<TGraphQLContext> | undefined;
188
188
  otelTracer?: otel.Tracer | undefined;
189
189
  otelRootSpanContext?: otel.Context | undefined;
190
- boot?: ((backend: Backend, parentSpan: otel.Span) => Promise<void>) | undefined;
190
+ boot?: ((db: InMemoryDatabase, parentSpan: otel.Span) => unknown | Promise<unknown>) | undefined;
191
191
  }) => Promise<Store<TGraphQLContext>>;
192
192
  //# sourceMappingURL=store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
package/dist/store.js CHANGED
@@ -1,23 +1,25 @@
1
1
  import { assertNever, makeNoopSpan, makeNoopTracer, shouldNeverHappen } from '@livestore/utils';
2
+ import { identity } from '@livestore/utils/effect';
2
3
  import * as otel from '@opentelemetry/api';
3
4
  import * as graphql from 'graphql';
4
5
  import { uniqueId } from 'lodash-es';
5
6
  import * as ReactDOM from 'react-dom';
7
+ import initSqlite3Wasm from 'sqlite-esm';
6
8
  import { v4 as uuid } from 'uuid';
7
- import { createBackend } from './backends/index.js';
8
9
  import { tableNameForComponentKey } from './componentKey.js';
9
10
  import { InMemoryDatabase } from './inMemoryDatabase.js';
11
+ import { migrateDb } from './migrations.js';
10
12
  import { getDurationMsFromSpan } from './otel.js';
11
13
  import { ReactiveGraph } from './reactive.js';
12
14
  import { LiveStoreGraphQLQuery } from './reactiveQueries/graphql.js';
13
15
  import { LiveStoreJSQuery } from './reactiveQueries/js.js';
14
16
  import { LiveStoreSQLQuery } from './reactiveQueries/sql.js';
15
- import { componentStateTables, loadSchema } from './schema.js';
16
- import { sql } from './util.js';
17
+ import { componentStateTables } from './schema.js';
18
+ import { isPromise, sql } from './util.js';
17
19
  export const RESET_DB_LOCAL_STORAGE_KEY = 'livestore-reset';
18
20
  const globalComponentKey = { _tag: 'singleton', componentName: '__global', id: 'singleton' };
19
21
  export class Store {
20
- constructor({ db, schema, backend, graphQLOptions, otelTracer, otelRootSpanContext, }) {
22
+ constructor({ db, schema, storage, graphQLOptions, otelTracer, otelRootSpanContext, }) {
21
23
  /**
22
24
  * Creates a reactive LiveStore SQL query
23
25
  *
@@ -298,7 +300,7 @@ export class Store {
298
300
  this.otel.tracer.startActiveSpan('LiveStore:processWrites', { attributes: { 'livestore.applyEventsLabel': label } }, otel.trace.setSpan(otel.context.active(), span), (span) => {
299
301
  try {
300
302
  const otelContext = otel.trace.setSpan(otel.context.active(), span);
301
- // TODO: what to do about backend transaction here?
303
+ // TODO: what to do about storage transaction here?
302
304
  this.inMemoryDB.txn(() => {
303
305
  for (const event of events) {
304
306
  try {
@@ -387,21 +389,35 @@ export class Store {
387
389
  };
388
390
  },
389
391
  },
392
+ RawSql: {
393
+ statement: ({ sql, writeTables }) => ({
394
+ sql,
395
+ writeTables,
396
+ argsAlreadyBound: false,
397
+ }),
398
+ prepareBindValues: ({ bindValues }) => bindValues,
399
+ },
390
400
  };
391
401
  const actionDefinition = actionDefinitions[eventType] ?? shouldNeverHappen(`Unknown event type: ${eventType}`);
392
402
  // Generate a fresh ID for the event
393
403
  const eventWithId = { id: uuid(), type: eventType, args };
394
404
  // Synchronously apply the event to the in-memory database
395
- const { durationMs } = this.inMemoryDB.applyEvent(eventWithId, actionDefinition, otelContext);
396
- // Asynchronously apply the event to a persistent backend (we're not awaiting this promise here)
397
- if (this.backend !== undefined) {
398
- this.backend.applyEvent(eventWithId, actionDefinition, span);
405
+ // const { durationMs } = this.inMemoryDB.applyEvent(eventWithId, actionDefinition, otelContext)
406
+ const { statement, bindValues } = eventToSql(eventWithId, actionDefinition);
407
+ const { durationMs } = this.inMemoryDB.execute(statement.sql, bindValues, statement.writeTables, {
408
+ otelContext,
409
+ });
410
+ // Asynchronously apply the event to a persistent storage (we're not awaiting this promise here)
411
+ if (this.storage !== undefined) {
412
+ // this.storage.applyEvent(eventWithId, actionDefinition, span)
413
+ this.storage.execute(statement.sql, bindValues, span);
399
414
  }
400
415
  // Uncomment to print a list of queries currently registered on the store
401
416
  // console.log(JSON.parse(JSON.stringify([...this.queries].map((q) => `${labelForKey(q.componentKey)}/${q.label}`))))
402
- const statement = typeof actionDefinition.statement === 'function'
403
- ? actionDefinition.statement(args)
404
- : actionDefinition.statement;
417
+ // const statement =
418
+ // typeof actionDefinition.statement === 'function'
419
+ // ? actionDefinition.statement(args)
420
+ // : actionDefinition.statement
405
421
  span.end();
406
422
  return { writeTables: statement.writeTables, durationMs };
407
423
  });
@@ -413,9 +429,9 @@ export class Store {
413
429
  */
414
430
  this.execute = async (query, params = {}, writeTables) => {
415
431
  this.inMemoryDB.execute(query, params, writeTables);
416
- if (this.backend !== undefined) {
432
+ if (this.storage !== undefined) {
417
433
  const parentSpan = otel.trace.getSpan(otel.context.active());
418
- this.backend.execute(query, params, parentSpan);
434
+ this.storage.execute(query, params, parentSpan);
419
435
  }
420
436
  };
421
437
  this.inMemoryDB = db;
@@ -429,7 +445,7 @@ export class Store {
429
445
  // TODO generalize the `tableRefs` concept to allow finer-grained refs
430
446
  this.tableRefs = {};
431
447
  this.activeQueries = new Set();
432
- this.backend = backend;
448
+ this.storage = storage;
433
449
  const applyEventsSpan = otelTracer.startSpan('LiveStore:applyEvents', {}, otelRootSpanContext);
434
450
  const otelApplyEventsSpanContext = otel.trace.setSpan(otel.context.active(), applyEventsSpan);
435
451
  const queriesSpan = otelTracer.startSpan('LiveStore:queries', {}, otelRootSpanContext);
@@ -469,71 +485,85 @@ Store.createStore = (storeOptions, parentSpan) => {
469
485
  });
470
486
  };
471
487
  /** Create a new LiveStore Store */
472
- export const createStore = async ({ schema, backendOptions, graphQLOptions, otelTracer = makeNoopTracer(), otelRootSpanContext = otel.context.active(), boot, }) => {
488
+ export const createStore = async ({ schema, loadStorage, graphQLOptions, otelTracer = makeNoopTracer(), otelRootSpanContext = otel.context.active(), boot, }) => {
473
489
  return otelTracer.startActiveSpan('createStore', {}, otelRootSpanContext, async (span) => {
474
490
  try {
475
- let persistedData;
476
- const backend = await createBackend(backendOptions, {
477
- otelTracer: otelTracer ?? makeNoopTracer(),
478
- parentSpan: otel.trace.getSpan(otelRootSpanContext ?? otel.context.active()) ?? makeNoopSpan(),
479
- });
480
- // if we're resetting the database, run boot here.
481
- let shouldResetDB = false;
482
- // Uncomment this line if you want to reset the database contents.
483
- // let shouldResetDB = true
484
- const existingTablesRaw = await backend.select(sql `SELECT * FROM sqlite_master WHERE type='table';`, undefined, span);
485
- const existingTables = existingTablesRaw.results.map((t) => t.name);
486
- const missingTables = Object.keys(schema.tables).filter((tableName) => !existingTables.includes(tableName));
487
- if (existingTables.length === 0) {
488
- console.log('No existing tables found, loading from schema');
489
- shouldResetDB = true;
490
- }
491
- else if (missingTables.length > 0 &&
492
- window.confirm(`Existing DB is missing ${missingTables.length} tables: ${missingTables.join(', ')}\n\nReset DB? This will reset all of the following tables to empty: ${Object.keys(schema).join(', ')}`)) {
493
- shouldResetDB = true;
494
- }
495
- if (localStorage.getItem(RESET_DB_LOCAL_STORAGE_KEY) !== null) {
496
- shouldResetDB = true;
497
- }
498
- if (shouldResetDB) {
499
- await loadSchema(backend, schema);
500
- localStorage.removeItem(RESET_DB_LOCAL_STORAGE_KEY);
501
- }
502
- if (boot) {
503
- await boot(backend, span);
504
- }
505
491
  const otelContext = otel.trace.setSpan(otel.context.active(), span);
506
- await otelTracer.startActiveSpan('backend-getPersistedData', {}, otelContext, async (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}`),
519
+ });
520
+ const [{ storage, persistedData }, sqlite3] = await Promise.all([loadStorageAndPersistedData(), loadSqlite3()]);
521
+ const db = InMemoryDatabase.load(persistedData, otelTracer, otelRootSpanContext, sqlite3);
522
+ // Proxy to `db` that also mirrors `execute` calls to `storage`
523
+ const dbProxy = new Proxy(db, {
524
+ get: (db, prop, receiver) => {
525
+ if (prop === 'execute') {
526
+ const execute = (query, bindValues, writeTables, options) => {
527
+ storage.execute(query, bindValues, span);
528
+ return db.execute(query, bindValues, writeTables, options);
529
+ };
530
+ return execute;
531
+ }
532
+ else {
533
+ return Reflect.get(db, prop, receiver);
534
+ }
535
+ },
536
+ });
537
+ otelTracer.startActiveSpan('migrateDb', {}, otelContext, async (span) => {
507
538
  try {
508
- persistedData = await backend.getPersistedData(span);
539
+ const otelContext = otel.trace.setSpan(otel.context.active(), span);
540
+ migrateDb({ db: dbProxy, schema, otelContext });
509
541
  }
510
542
  finally {
511
543
  span.end();
512
544
  }
513
545
  });
514
- const db = await InMemoryDatabase.load(persistedData, otelTracer, otelRootSpanContext);
515
- configureSQLite(db);
546
+ if (boot !== undefined) {
547
+ const booting = boot(dbProxy, span);
548
+ // NOTE only awaiting if it's actually a promise to avoid unnecessary async/await
549
+ if (isPromise(booting)) {
550
+ await booting;
551
+ }
552
+ }
516
553
  // TODO: we can't apply the schema at this point, we've already loaded persisted data!
517
554
  // Think about what to do about this case.
518
555
  // await applySchema(db, schema)
519
- return Store.createStore({ db, schema, backend, graphQLOptions, otelTracer, otelRootSpanContext }, span);
556
+ return Store.createStore({ db, schema, storage, graphQLOptions, otelTracer, otelRootSpanContext }, span);
520
557
  }
521
558
  finally {
522
559
  span.end();
523
560
  }
524
561
  });
525
562
  };
526
- /** Set up SQLite performance; hasn't been super carefully optimized yet. */
527
- const configureSQLite = (db) => {
528
- db.execute(
529
- // TODO: revisit these tuning parameters for max performance
530
- sql `
531
- PRAGMA page_size=32768;
532
- PRAGMA cache_size=10000;
533
- PRAGMA journal_mode='MEMORY'; -- we don't flush to disk before committing a write
534
- PRAGMA synchronous='OFF';
535
- PRAGMA temp_store='MEMORY';
536
- PRAGMA foreign_keys='ON'; -- we want foreign key constraints to be enforced
537
- `);
563
+ const eventToSql = (event, eventDefinition) => {
564
+ const statement = typeof eventDefinition.statement === 'function' ? eventDefinition.statement(event.args) : eventDefinition.statement;
565
+ const prepareBindValues = eventDefinition.prepareBindValues ?? identity;
566
+ const bindValues = typeof eventDefinition.statement === 'function' && statement.argsAlreadyBound ? {} : prepareBindValues(event.args);
567
+ return { statement, bindValues };
538
568
  };
539
569
  //# sourceMappingURL=store.js.map