@moltendb-web/core 0.1.0-alpha.9 → 0.1.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # MoltenDB Web
2
2
 
3
3
  <div align="center">
4
- <img src="./dist/assets/logo.png" alt="MoltenDB Logo" width="64"/>
4
+ <img src="../../assets/logo.png" alt="MoltenDB Logo" width="64"/>
5
5
 
6
6
  ### 🌋 The Embedded Database for the Modern Web
7
7
  **High-performance Rust engine compiled to WASM. Persistent storage via OPFS.**
@@ -50,7 +50,30 @@ npm install @moltendb-web/core
50
50
  # Install the chainable query builder
51
51
  npm install @moltendb-web/query
52
52
  ```
53
+ 📦 **Bundler Setup**
53
54
 
55
+ MoltenDB handles its own Web Workers and WASM loading automatically. However, depending on your build tool, you may need a tiny config tweak to ensure it serves the static files correctly.
56
+
57
+ **For Vite:**
58
+ Exclude the core package from pre-bundling in your vite.config.js:
59
+
60
+ ```js
61
+ // vite.config.js`
62
+ export default defineConfig({
63
+ optimizeDeps: { exclude: ['@moltendb-web/core'] }
64
+ });
65
+ ```
66
+
67
+ **For Webpack 5 (Next.js, Create React App):**
68
+ Ensure Webpack treats the `.wasm` binary as a static resource in `webpack.config.js`:
69
+
70
+ ```js
71
+ module.exports = {
72
+ module: {
73
+ rules: [{ test: /\.wasm$/, type: 'asset/resource' }]
74
+ }
75
+ };
76
+ ```
54
77
  ---
55
78
 
56
79
  # Quick Start
@@ -62,12 +85,11 @@ TypeScript
62
85
  import { MoltenDB } from '@moltendb-web/core';
63
86
  import { MoltenDBClient, WorkerTransport } from '@moltendb-web/query';
64
87
 
65
- const workerUrl = new URL('@moltendb-web/core/worker', import.meta.url).href;
66
- const db = new MoltenDB('moltendb_demo', { syncEnabled: false, workerUrl });
88
+ const db = new MoltenDB('moltendb_demo');
67
89
  await db.init();
68
90
 
69
91
  // Connect the query builder to the WASM worker
70
- const client = new MoltenDBClient(new WorkerTransport(db.worker));
92
+ const client = new MoltenDBClient(db);
71
93
 
72
94
  // 2. Insert and Query
73
95
 
@@ -243,7 +265,7 @@ This monorepo contains the following packages:
243
265
 
244
266
  ## Roadmap
245
267
 
246
- - [ ] **Multi-Tab Sync:** Leader election for multiple tabs to share a single OPFS instance.
268
+ - [ ] ~~**Multi-Tab Sync:** Leader election for multiple tabs to share a single OPFS instance.~~ ✅
247
269
  - [ ] **Delta Sync:** Automatic two-way sync with the MoltenDB Rust server.
248
270
  - [ ] **Analytics functionality:** Run analytics queries straight in the browser.
249
271
 
@@ -256,6 +278,4 @@ MoltenDB is licensed under the **Business Source License 1.1**.
256
278
 
257
279
  For commercial licensing or questions: [maximilian.both27@outlook.com](mailto:maximilian.both27@outlook.com)
258
280
 
259
- ---
260
281
 
261
- Created with 🌋 by Maximilian Both. Coming to the world on the Equinox.
package/dist/index.d.ts CHANGED
@@ -1,56 +1,55 @@
1
1
  export interface MoltenDBOptions {
2
- /** URL or path to moltendb-worker.js. Defaults to './moltendb-worker.js'. */
3
- workerUrl?: string | URL;
4
- /** Enable WebSocket sync with a MoltenDB server. Default: false. */
5
- syncEnabled?: boolean;
6
- /** WebSocket server URL. Default: 'wss://localhost:3000/ws'. */
7
- serverUrl?: string;
8
- /** Sync batch flush interval in ms. Default: 5000. */
9
- syncIntervalMs?: number;
10
- /** JWT token for WebSocket authentication. */
11
- authToken?: string;
2
+ /** URL or path to moltendb-worker.js. */
3
+ workerUrl?: string | URL;
4
+ /** Enable WebSocket sync with a MoltenDB server. Default: false. */
5
+ syncEnabled?: boolean;
6
+ /** WebSocket server URL. Default: 'wss://localhost:1538/ws'. */
7
+ serverUrl?: string;
8
+ /** Sync batch flush interval in ms. Default: 5000. */
9
+ syncIntervalMs?: number;
10
+ /** JWT token for WebSocket authentication. */
11
+ authToken?: string;
12
12
  }
13
-
14
13
  export type SyncCallback = (update: {
15
- event: 'change' | 'delete' | 'drop';
16
- collection: string;
17
- key: string;
18
- new_v: number | null;
14
+ event: 'change' | 'delete' | 'drop';
15
+ collection: string;
16
+ key: string;
17
+ new_v: number | null;
19
18
  }) => void;
20
-
21
- export class MoltenDB {
22
- readonly dbName: string;
23
- readonly worker: Worker | null;
24
-
25
- constructor(dbName?: string, options?: MoltenDBOptions);
26
-
27
- /** Initialise the Web Worker and open the OPFS database. */
28
- init(): Promise<void>;
29
-
30
- /** Send a raw message to the worker. */
31
- sendMessage(action: string, params?: Record<string, unknown>): Promise<unknown>;
32
-
33
- /** Insert / upsert one document. */
34
- set(collection: string, key: string, value: Record<string, unknown>, options?: { skipSync?: boolean }): Promise<void>;
35
-
36
- /** Fetch a single document by key. */
37
- get(collection: string, key: string): Promise<unknown>;
38
-
39
- /** Fetch all documents in a collection. */
40
- getAll(collection: string): Promise<unknown>;
41
-
42
- /** Delete a document by key. */
43
- delete(collection: string, key: string, options?: { skipSync?: boolean }): Promise<void>;
44
-
45
- /** Compact the OPFS log file. */
46
- compact(): Promise<unknown>;
47
-
48
- /** Subscribe to real-time server push events. Returns an unsubscribe function. */
49
- onSync(callback: SyncCallback): () => void;
50
-
51
- /** Close the WebSocket connection and stop the sync timer. */
52
- disconnect(): void;
53
-
54
- /** Terminate the Web Worker (and disconnect sync). */
55
- terminate(): void;
19
+ export declare class MoltenDB {
20
+ readonly dbName: string;
21
+ readonly workerUrl?: string | URL;
22
+ worker: Worker | null;
23
+ private messageId;
24
+ private pendingRequests;
25
+ isLeader: boolean;
26
+ private bc;
27
+ private syncEnabled;
28
+ private serverUrl;
29
+ private syncIntervalMs;
30
+ private authToken?;
31
+ private ws;
32
+ private syncCallbacks;
33
+ private syncQueue;
34
+ private syncTimer;
35
+ /** Hook to listen to native real-time DB mutations (works on all tabs) */
36
+ onEvent?: (event: any) => void;
37
+ constructor(dbName?: string, options?: MoltenDBOptions);
38
+ init(): Promise<void>;
39
+ private startAsLeader;
40
+ private startAsFollower;
41
+ sendMessage(action: string, payload?: Record<string, unknown>): Promise<any>;
42
+ set(collection: string, key: string, value: Record<string, unknown>, options?: {
43
+ skipSync?: boolean;
44
+ }): Promise<void>;
45
+ get(collection: string, key: string): Promise<unknown>;
46
+ getAll(collection: string): Promise<unknown>;
47
+ delete(collection: string, key: string, options?: {
48
+ skipSync?: boolean;
49
+ }): Promise<void>;
50
+ compact(): Promise<unknown>;
51
+ private startSync;
52
+ onSyncEvent(callback: SyncCallback): void;
53
+ disconnect(): void;
54
+ terminate(): void;
56
55
  }
package/dist/index.js CHANGED
@@ -1,176 +1,219 @@
1
- /**
2
- * MoltenDB main-thread client.
3
- *
4
- * Usage:
5
- * import { MoltenDB } from 'moltendb-wasm';
6
- *
7
- * const db = new MoltenDB('my-db', {
8
- * // Required: URL or path to the moltendb-worker.js file.
9
- * // With a bundler: new URL('moltendb-wasm/worker', import.meta.url)
10
- * // Plain script: '/node_modules/moltendb-wasm/dist/moltendb-worker.js'
11
- * workerUrl: new URL('moltendb-wasm/worker', import.meta.url),
12
- * });
13
- * await db.init();
14
- */
15
1
  export class MoltenDB {
16
- /**
17
- * @param {string} dbName - OPFS file name (unique per database).
18
- * @param {object} [options]
19
- * @param {string|URL} [options.workerUrl] - URL to moltendb-worker.js.
20
- * Defaults to './moltendb-worker.js' (works when served from the same directory).
21
- * @param {boolean} [options.syncEnabled=false] - Enable WebSocket sync.
22
- * @param {string} [options.serverUrl='wss://localhost:3000/ws'] - WS server URL.
23
- * @param {number} [options.syncIntervalMs=5000] - Sync batch flush interval.
24
- * @param {string} [options.authToken] - JWT token for WS authentication.
25
- */
2
+ dbName;
3
+ workerUrl;
4
+ worker = null;
5
+ messageId = 0;
6
+ pendingRequests = new Map();
7
+ // Multi-tab Sync State
8
+ isLeader = false;
9
+ bc;
10
+ // Server Sync State
11
+ syncEnabled;
12
+ serverUrl;
13
+ syncIntervalMs;
14
+ authToken;
15
+ ws = null;
16
+ syncCallbacks = [];
17
+ syncQueue = [];
18
+ syncTimer = null;
19
+ /** ⚡ Hook to listen to native real-time DB mutations (works on all tabs) */
20
+ onEvent;
26
21
  constructor(dbName = 'moltendb', options = {}) {
27
- this.dbName = dbName;
28
- this.workerUrl = options.workerUrl ?? './moltendb-worker.js';
29
- this.worker = null;
30
- this.messageId = 0;
31
- this.pendingRequests = new Map();
32
-
33
- this.syncEnabled = options.syncEnabled ?? false;
34
- this.serverUrl = options.serverUrl ?? 'wss://localhost:3000/ws';
22
+ this.dbName = dbName;
23
+ this.workerUrl = options.workerUrl;
24
+ this.syncEnabled = options.syncEnabled ?? false;
25
+ this.serverUrl = options.serverUrl ?? 'wss://localhost:3000/ws';
35
26
  this.syncIntervalMs = options.syncIntervalMs ?? 5000;
36
- this.authToken = options.authToken ?? null;
37
-
38
- this.ws = null;
39
- this.syncCallbacks = new Set();
40
- this.syncQueue = [];
41
- this.syncTimer = null;
27
+ this.authToken = options.authToken;
42
28
  }
43
-
44
- /** Initialise the Web Worker and open the OPFS database. */
45
29
  async init() {
46
- return new Promise((resolve, reject) => {
47
- this.worker = new Worker(this.workerUrl, { type: 'module' });
48
-
49
- this.worker.onmessage = (event) => {
50
- const { id, result, error } = event.data;
51
- const pending = this.pendingRequests.get(id);
52
- if (!pending) return;
53
- this.pendingRequests.delete(id);
54
- if (error) pending.reject(new Error(error));
55
- else pending.resolve(result);
56
- };
57
-
58
- this.worker.onerror = (err) => {
59
- console.error('[MoltenDB] Worker error:', err);
60
- reject(err);
61
- };
62
-
63
- this.sendMessage('init', { dbName: this.dbName })
64
- .then(() => this.syncEnabled ? this.connectSync() : undefined)
65
- .then(resolve)
66
- .catch(reject);
30
+ this.bc = new BroadcastChannel(`moltendb_channel_${this.dbName}`);
31
+ return new Promise((resolveInit) => {
32
+ // 1. Try to grab the lock immediately (Leader Election)
33
+ navigator.locks.request(`moltendb_lock_${this.dbName}`, { ifAvailable: true }, async (lock) => {
34
+ if (lock) {
35
+ // We got the lock! We are the active DB host.
36
+ await this.startAsLeader();
37
+ resolveInit();
38
+ // Return a promise that never resolves to hold the lock until the tab closes
39
+ return new Promise(() => { });
40
+ }
41
+ else {
42
+ // Lock is taken. We are a proxy follower.
43
+ this.startAsFollower();
44
+ resolveInit();
45
+ // 2. Queue up in the background. If the Leader tab closes, this lock resolves!
46
+ navigator.locks.request(`moltendb_lock_${this.dbName}`, async (fallbackLock) => {
47
+ console.log(`[MoltenDB] Previous leader disconnected. Promoting this tab to Leader.`);
48
+ await this.startAsLeader();
49
+ return new Promise(() => { }); // Hold lock
50
+ });
51
+ }
52
+ });
67
53
  });
68
54
  }
69
-
70
- /**
71
- * Send a raw message to the worker and return a Promise for the result.
72
- * @param {string} action
73
- * @param {object} [params]
74
- */
75
- sendMessage(action, params = {}) {
76
- return new Promise((resolve, reject) => {
55
+ async startAsLeader() {
56
+ this.isLeader = true;
57
+ if (this.worker)
58
+ this.worker.terminate(); // Clean slate if promoted
59
+ // We must inline `new URL` directly inside `new Worker` so bundlers catch it!
60
+ if (this.workerUrl) {
61
+ this.worker = new Worker(this.workerUrl, { type: 'module', name: `moltendb-${this.dbName}-leader` });
62
+ }
63
+ else {
64
+ this.worker = new Worker(new URL('./moltendb-worker.js', import.meta.url), { type: 'module', name: `moltendb-${this.dbName}-leader` });
65
+ }
66
+ // Handle messages strictly from our local Worker
67
+ this.worker.onmessage = (e) => {
68
+ const data = e.data;
69
+ if (data.type === 'event') {
70
+ // Trigger local UI hook
71
+ if (this.onEvent)
72
+ this.onEvent(data);
73
+ // Broadcast the native event to all Follower tabs
74
+ this.bc.postMessage(data);
75
+ return;
76
+ }
77
+ // Resolve pending local promises
78
+ const req = this.pendingRequests.get(data.id);
79
+ if (req) {
80
+ if (data.error)
81
+ req.reject(new Error(data.error));
82
+ else
83
+ req.resolve(data.result);
84
+ this.pendingRequests.delete(data.id);
85
+ }
86
+ };
87
+ // Initialize the WASM Engine
88
+ await new Promise((resolve, reject) => {
77
89
  const id = this.messageId++;
78
90
  this.pendingRequests.set(id, { resolve, reject });
79
- this.worker.postMessage({ id, action, ...params });
91
+ this.worker.postMessage({ id, action: 'init', dbName: this.dbName });
80
92
  });
81
- }
82
-
83
- // ── WebSocket sync ────────────────────────────────────────────────────────
84
-
85
- connectSync() {
86
- return new Promise((resolve, reject) => {
87
- this.ws = new WebSocket(this.serverUrl);
88
-
89
- this.ws.onopen = () => {
90
- if (this.authToken) {
91
- this.ws.send(JSON.stringify({ action: 'AUTH', token: this.authToken }));
93
+ // Listen to the BroadcastChannel for queries coming from Follower tabs
94
+ this.bc.onmessage = async (e) => {
95
+ const msg = e.data;
96
+ if (msg.type === 'query' && msg.action) {
97
+ try {
98
+ const result = await this.sendMessage(msg.action, msg.payload);
99
+ this.bc.postMessage({ type: 'response', id: msg.id, result });
92
100
  }
93
- if (this.syncTimer) clearInterval(this.syncTimer);
94
- this.syncTimer = setInterval(() => this.flushSyncQueue(), this.syncIntervalMs);
95
- resolve();
96
- };
97
-
98
- this.ws.onmessage = (event) => {
99
- try { this.handleServerUpdate(JSON.parse(event.data)); }
100
- catch (e) { console.error('[MoltenDB] Failed to parse server message:', e); }
101
- };
102
-
103
- this.ws.onclose = () => {
104
- if (this.syncTimer) clearInterval(this.syncTimer);
105
- setTimeout(() => this.connectSync(), 3000);
106
- };
107
-
108
- this.ws.onerror = (err) => reject(err);
109
- });
110
- }
111
-
112
- handleServerUpdate(update) {
113
- if (update.event === 'change' && update.collection && update.key) {
114
- // Re-fetch the updated document from the server and apply locally.
115
- // (The WS push only carries the key + new _v, not the full document.)
101
+ catch (err) {
102
+ this.bc.postMessage({ type: 'response', id: msg.id, error: err.message });
103
+ }
104
+ }
105
+ };
106
+ // If backend sync is enabled, only the Leader manages the WebSocket
107
+ if (this.syncEnabled) {
108
+ this.startSync();
116
109
  }
117
- this.syncCallbacks.forEach(cb => cb(update));
118
110
  }
119
-
120
- /** Subscribe to real-time server push events. Returns an unsubscribe fn. */
121
- onSync(callback) {
122
- this.syncCallbacks.add(callback);
123
- return () => this.syncCallbacks.delete(callback);
111
+ startAsFollower() {
112
+ this.isLeader = false;
113
+ // We don't need a worker, we rely on the Leader.
114
+ if (this.worker) {
115
+ this.worker.terminate();
116
+ this.worker = null;
117
+ }
118
+ // Listen to the BroadcastChannel for answers from the Leader
119
+ this.bc.onmessage = (e) => {
120
+ const data = e.data;
121
+ if (data.type === 'event') {
122
+ // Trigger local UI hook as if it happened in this tab
123
+ if (this.onEvent)
124
+ this.onEvent(data);
125
+ return;
126
+ }
127
+ if (data.type === 'response') {
128
+ // Resolve our proxied promises
129
+ const req = this.pendingRequests.get(data.id);
130
+ if (req) {
131
+ if (data.error)
132
+ req.reject(new Error(data.error));
133
+ else
134
+ req.resolve(data.result);
135
+ this.pendingRequests.delete(data.id);
136
+ }
137
+ }
138
+ };
124
139
  }
125
-
126
- flushSyncQueue() {
127
- if (!this.syncQueue.length || !this.ws || this.ws.readyState !== WebSocket.OPEN) return;
128
- const batch = this.syncQueue.splice(0);
129
- this.ws.send(JSON.stringify({ action: 'set', operations: batch }));
140
+ async sendMessage(action, payload) {
141
+ const id = this.messageId++;
142
+ return new Promise((resolve, reject) => {
143
+ this.pendingRequests.set(id, { resolve, reject });
144
+ if (this.isLeader && this.worker) {
145
+ // Direct execution on the local Worker
146
+ this.worker.postMessage({ id, action, ...payload });
147
+ }
148
+ else {
149
+ // Proxy the request to the Leader tab
150
+ this.bc.postMessage({ type: 'query', id, action, payload });
151
+ }
152
+ });
130
153
  }
131
-
132
154
  // ── Convenience CRUD helpers ──────────────────────────────────────────────
133
-
134
- /** Insert / upsert one document. */
135
155
  async set(collection, key, value, options = {}) {
136
156
  await this.sendMessage('set', { collection, data: { [key]: value } });
137
- if (this.syncEnabled && !options.skipSync) {
157
+ if (this.syncEnabled && !options.skipSync && this.isLeader) {
138
158
  this.syncQueue.push({ action: 'set', collection, data: { [key]: value } });
139
159
  }
140
160
  }
141
-
142
- /** Fetch a single document by key. */
143
161
  get(collection, key) {
144
162
  return this.sendMessage('get', { collection, keys: key });
145
163
  }
146
-
147
- /** Fetch all documents in a collection. */
148
164
  getAll(collection) {
149
165
  return this.sendMessage('get', { collection });
150
166
  }
151
-
152
- /** Delete a document by key. */
153
167
  async delete(collection, key, options = {}) {
154
168
  await this.sendMessage('delete', { collection, keys: key });
155
- if (this.syncEnabled && !options.skipSync) {
169
+ if (this.syncEnabled && !options.skipSync && this.isLeader) {
156
170
  this.syncQueue.push({ action: 'delete', collection, keys: key });
157
171
  }
158
172
  }
159
-
160
- /** Compact the OPFS log file. */
161
173
  compact() {
162
174
  return this.sendMessage('compact');
163
175
  }
164
-
165
- /** Close the WebSocket connection and stop the sync timer. */
176
+ // ── Server Sync Implementation (Leader Only) ──────────────────────────────
177
+ startSync() {
178
+ this.ws = new WebSocket(this.serverUrl);
179
+ this.ws.onopen = () => {
180
+ if (this.authToken) {
181
+ this.ws?.send(JSON.stringify({ type: 'auth', token: this.authToken }));
182
+ }
183
+ };
184
+ this.ws.onmessage = (e) => {
185
+ try {
186
+ const msg = JSON.parse(e.data);
187
+ if (msg.event) {
188
+ for (const cb of this.syncCallbacks)
189
+ cb(msg);
190
+ }
191
+ }
192
+ catch (err) { }
193
+ };
194
+ this.syncTimer = setInterval(async () => {
195
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN)
196
+ return;
197
+ if (this.syncQueue.length === 0)
198
+ return;
199
+ const batch = this.syncQueue.splice(0, this.syncQueue.length);
200
+ this.ws.send(JSON.stringify({ type: 'batch', operations: batch }));
201
+ }, this.syncIntervalMs);
202
+ }
203
+ onSyncEvent(callback) {
204
+ this.syncCallbacks.push(callback);
205
+ }
166
206
  disconnect() {
167
- if (this.syncTimer) clearInterval(this.syncTimer);
168
- if (this.ws) this.ws.close();
207
+ if (this.syncTimer)
208
+ clearInterval(this.syncTimer);
209
+ if (this.ws)
210
+ this.ws.close();
211
+ if (this.bc)
212
+ this.bc.close();
169
213
  }
170
-
171
- /** Terminate the Web Worker (and disconnect sync). */
172
214
  terminate() {
173
215
  this.disconnect();
174
- if (this.worker) this.worker.terminate();
216
+ if (this.worker)
217
+ this.worker.terminate();
175
218
  }
176
219
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,30 +1,36 @@
1
- // MoltenDB Web Worker — auto-generated by moltendb-wasm build script
2
- // Do not edit directly; edit moltendb-wasm/scripts/build.mjs instead.
3
1
  import init, { WorkerDb } from './moltendb.js';
4
-
5
- let db = null;
6
-
7
- self.onmessage = async (event) => {
8
- const { id, action, ...params } = event.data;
9
-
10
- try {
11
- if (!db && action === 'init') {
2
+ let db;
3
+ self.onmessage = async (e) => {
4
+ const { id, action, ...payload } = e.data;
5
+ // --- Initialization Phase ---
6
+ if (action === 'init') {
7
+ try {
12
8
  await init();
13
- db = await new WorkerDb(params.dbName || 'moltendb');
14
- self.postMessage({ id, result: { status: 'initialized' } });
15
- return;
9
+ db = await new WorkerDb(payload.dbName);
10
+ // THE NATIVE FEED: Listen to Rust and broadcast to the main thread
11
+ db.subscribe((eventStr) => {
12
+ try {
13
+ const eventData = JSON.parse(eventStr);
14
+ // Use type: 'event' so the transport knows it's an unsolicited broadcast
15
+ self.postMessage({ type: 'event', ...eventData });
16
+ }
17
+ catch (err) {
18
+ console.error('[MoltenDB Worker] Failed to parse event', err);
19
+ }
20
+ });
21
+ self.postMessage({ id, result: { status: 'ok' } });
16
22
  }
17
-
18
- if (!db) {
19
- throw new Error('Database not initialized. Send an "init" message first.');
23
+ catch (error) {
24
+ self.postMessage({ id, error: String(error) });
20
25
  }
21
-
22
- // Pass action + params but NOT id so the Rust validator does not see
23
- // 'id' as an unknown property.
24
- const result = db.handle_message({ action, ...params });
26
+ return;
27
+ }
28
+ // --- Standard Request/Response Phase ---
29
+ try {
30
+ const result = db.handle_message({ action, ...payload });
25
31
  self.postMessage({ id, result });
26
-
27
- } catch (error) {
28
- self.postMessage({ id, error: error.toString() });
32
+ }
33
+ catch (error) {
34
+ self.postMessage({ id, error: String(error) });
29
35
  }
30
36
  };
@@ -76,6 +76,12 @@ export class WorkerDb {
76
76
  * Each unique name is a separate database file in the browser's OPFS storage.
77
77
  */
78
78
  constructor(db_name: string);
79
+ /**
80
+ * Subscribe to real-time database changes.
81
+ * The provided JavaScript function will be called with a JSON string
82
+ * representing the mutation event.
83
+ */
84
+ subscribe(callback: Function): void;
79
85
  }
80
86
 
81
87
  export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
@@ -86,9 +92,10 @@ export interface InitOutput {
86
92
  readonly workerdb_analytics: (a: number, b: number, c: number, d: number) => void;
87
93
  readonly workerdb_handle_message: (a: number, b: number, c: number) => void;
88
94
  readonly workerdb_new: (a: number, b: number) => number;
89
- readonly __wasm_bindgen_func_elem_3598: (a: number, b: number) => void;
90
- readonly __wasm_bindgen_func_elem_3677: (a: number, b: number, c: number, d: number) => void;
91
- readonly __wasm_bindgen_func_elem_3690: (a: number, b: number, c: number, d: number) => void;
95
+ readonly workerdb_subscribe: (a: number, b: number) => void;
96
+ readonly __wasm_bindgen_func_elem_3624: (a: number, b: number) => void;
97
+ readonly __wasm_bindgen_func_elem_3703: (a: number, b: number, c: number, d: number) => void;
98
+ readonly __wasm_bindgen_func_elem_3716: (a: number, b: number, c: number, d: number) => void;
92
99
  readonly __wbindgen_export: (a: number, b: number) => number;
93
100
  readonly __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
94
101
  readonly __wbindgen_export3: (a: number) => void;
package/dist/moltendb.js CHANGED
@@ -131,6 +131,15 @@ export class WorkerDb {
131
131
  const ret = wasm.workerdb_new(ptr0, len0);
132
132
  return takeObject(ret);
133
133
  }
134
+ /**
135
+ * Subscribe to real-time database changes.
136
+ * The provided JavaScript function will be called with a JSON string
137
+ * representing the mutation event.
138
+ * @param {Function} callback
139
+ */
140
+ subscribe(callback) {
141
+ wasm.workerdb_subscribe(this.__wbg_ptr, addHeapObject(callback));
142
+ }
134
143
  }
135
144
  if (Symbol.dispose) WorkerDb.prototype[Symbol.dispose] = WorkerDb.prototype.free;
136
145
 
@@ -377,7 +386,7 @@ function __wbg_get_imports() {
377
386
  const a = state0.a;
378
387
  state0.a = 0;
379
388
  try {
380
- return __wasm_bindgen_func_elem_3690(a, state0.b, arg0, arg1);
389
+ return __wasm_bindgen_func_elem_3716(a, state0.b, arg0, arg1);
381
390
  } finally {
382
391
  state0.a = a;
383
392
  }
@@ -497,8 +506,8 @@ function __wbg_get_imports() {
497
506
  return ret;
498
507
  }, arguments); },
499
508
  __wbindgen_cast_0000000000000001: function(arg0, arg1) {
500
- // Cast intrinsic for `Closure(Closure { dtor_idx: 661, function: Function { arguments: [Externref], shim_idx: 672, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
501
- const ret = makeMutClosure(arg0, arg1, wasm.__wasm_bindgen_func_elem_3598, __wasm_bindgen_func_elem_3677);
509
+ // Cast intrinsic for `Closure(Closure { dtor_idx: 663, function: Function { arguments: [Externref], shim_idx: 674, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
510
+ const ret = makeMutClosure(arg0, arg1, wasm.__wasm_bindgen_func_elem_3624, __wasm_bindgen_func_elem_3703);
502
511
  return addHeapObject(ret);
503
512
  },
504
513
  __wbindgen_cast_0000000000000002: function(arg0) {
@@ -535,10 +544,10 @@ function __wbg_get_imports() {
535
544
  };
536
545
  }
537
546
 
538
- function __wasm_bindgen_func_elem_3677(arg0, arg1, arg2) {
547
+ function __wasm_bindgen_func_elem_3703(arg0, arg1, arg2) {
539
548
  try {
540
549
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
541
- wasm.__wasm_bindgen_func_elem_3677(retptr, arg0, arg1, addHeapObject(arg2));
550
+ wasm.__wasm_bindgen_func_elem_3703(retptr, arg0, arg1, addHeapObject(arg2));
542
551
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
543
552
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
544
553
  if (r1) {
@@ -549,8 +558,8 @@ function __wasm_bindgen_func_elem_3677(arg0, arg1, arg2) {
549
558
  }
550
559
  }
551
560
 
552
- function __wasm_bindgen_func_elem_3690(arg0, arg1, arg2, arg3) {
553
- wasm.__wasm_bindgen_func_elem_3690(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
561
+ function __wasm_bindgen_func_elem_3716(arg0, arg1, arg2, arg3) {
562
+ wasm.__wasm_bindgen_func_elem_3716(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
554
563
  }
555
564
 
556
565
  const WorkerDbFinalization = (typeof FinalizationRegistry === 'undefined')
Binary file
@@ -5,9 +5,10 @@ export const __wbg_workerdb_free: (a: number, b: number) => void;
5
5
  export const workerdb_analytics: (a: number, b: number, c: number, d: number) => void;
6
6
  export const workerdb_handle_message: (a: number, b: number, c: number) => void;
7
7
  export const workerdb_new: (a: number, b: number) => number;
8
- export const __wasm_bindgen_func_elem_3598: (a: number, b: number) => void;
9
- export const __wasm_bindgen_func_elem_3677: (a: number, b: number, c: number, d: number) => void;
10
- export const __wasm_bindgen_func_elem_3690: (a: number, b: number, c: number, d: number) => void;
8
+ export const workerdb_subscribe: (a: number, b: number) => void;
9
+ export const __wasm_bindgen_func_elem_3624: (a: number, b: number) => void;
10
+ export const __wasm_bindgen_func_elem_3703: (a: number, b: number, c: number, d: number) => void;
11
+ export const __wasm_bindgen_func_elem_3716: (a: number, b: number, c: number, d: number) => void;
11
12
  export const __wbindgen_export: (a: number, b: number) => number;
12
13
  export const __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
13
14
  export const __wbindgen_export3: (a: number) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moltendb-web/core",
3
- "version": "0.1.0-alpha.9",
3
+ "version": "0.1.0-beta.2",
4
4
  "description": "MoltenDB WASM runtime — the database engine, Web Worker, and main-thread client in one package.",
5
5
  "type": "module",
6
6
  "author": "Maximilian Both <maximilian.both27@outlook.com>",
@@ -25,8 +25,13 @@
25
25
  },
26
26
  "main": "./dist/index.js",
27
27
  "types": "./dist/index.d.ts",
28
+ "scripts": {
29
+ "build": "tsc",
30
+ "dev": "tsc --watch",
31
+ "typecheck": "tsc --noEmit"
32
+ },
28
33
  "devDependencies": {
29
- "typescript": "^6.0.1-rc"
34
+ "typescript": "^6.0.2"
30
35
  },
31
36
  "keywords": [
32
37
  "database",
@@ -38,4 +43,4 @@
38
43
  "indexeddb",
39
44
  "embedded"
40
45
  ]
41
- }
46
+ }
Binary file