reflectdb 0.1.0 → 0.1.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.
Files changed (61) hide show
  1. package/README.md +500 -40
  2. package/dist/cjs/client/index.cjs +32 -17
  3. package/dist/cjs/client/index.d.cts +18 -3
  4. package/dist/cjs/client/storage/indexeddb.d.cts +1 -1
  5. package/dist/cjs/core/index.cjs +28 -28
  6. package/dist/cjs/core/index.d.cts +21 -9
  7. package/dist/cjs/react/index.cjs +48 -33
  8. package/dist/cjs/react/index.d.cts +23 -5
  9. package/dist/cjs/server/drizzle.cjs +2 -2
  10. package/dist/cjs/server/drizzle.d.cts +1 -1
  11. package/dist/cjs/server/ephemeral/index.cjs +180 -0
  12. package/dist/cjs/server/ephemeral/index.d.cts +102 -0
  13. package/dist/cjs/server/ephemeral/redis.cjs +226 -0
  14. package/dist/cjs/server/ephemeral/redis.d.cts +136 -0
  15. package/dist/cjs/server/index.cjs +238 -87
  16. package/dist/cjs/server/index.d.cts +196 -5
  17. package/dist/cjs/svelte/index.cjs +34 -19
  18. package/dist/cjs/svelte/index.d.cts +18 -3
  19. package/dist/cjs/transport/bun-ws.cjs +9 -9
  20. package/dist/cjs/transport/bun-ws.d.cts +1 -1
  21. package/dist/cjs/transport/polling.cjs +11 -11
  22. package/dist/cjs/transport/polling.d.cts +1 -1
  23. package/dist/cjs/transport/sse.cjs +11 -11
  24. package/dist/cjs/transport/sse.d.cts +1 -1
  25. package/dist/cjs/transport/ws.cjs +11 -11
  26. package/dist/cjs/transport/ws.d.cts +1 -1
  27. package/dist/cjs/vanilla/index.cjs +34 -19
  28. package/dist/cjs/vanilla/index.d.cts +18 -3
  29. package/dist/client/index.d.ts +18 -3
  30. package/dist/client/index.js +7 -7
  31. package/dist/client/storage/indexeddb.d.ts +1 -1
  32. package/dist/client/storage/indexeddb.js +1 -1
  33. package/dist/core/index.d.ts +21 -9
  34. package/dist/core/index.js +20 -20
  35. package/dist/react/index.d.ts +23 -5
  36. package/dist/react/index.js +23 -23
  37. package/dist/server/drizzle.d.ts +1 -1
  38. package/dist/server/drizzle.js +3 -3
  39. package/dist/server/ephemeral/index.d.ts +102 -0
  40. package/dist/server/ephemeral/index.js +9 -0
  41. package/dist/server/ephemeral/redis.d.ts +136 -0
  42. package/dist/server/ephemeral/redis.js +186 -0
  43. package/dist/server/index.d.ts +196 -5
  44. package/dist/server/index.js +184 -163
  45. package/dist/shared/{esm-ytrd3hbq.js → esm-8qbr4y0d.js} +18 -3
  46. package/dist/shared/{esm-wkwx6bd9.js → esm-ck88h30s.js} +10 -10
  47. package/dist/shared/esm-g0marxk7.js +134 -0
  48. package/dist/svelte/index.d.ts +18 -3
  49. package/dist/svelte/index.js +9 -9
  50. package/dist/transport/bun-ws.d.ts +1 -1
  51. package/dist/transport/bun-ws.js +1 -1
  52. package/dist/transport/polling.d.ts +1 -1
  53. package/dist/transport/polling.js +3 -3
  54. package/dist/transport/sse.d.ts +1 -1
  55. package/dist/transport/sse.js +3 -3
  56. package/dist/transport/ws.d.ts +1 -1
  57. package/dist/transport/ws.js +3 -3
  58. package/dist/vanilla/index.d.ts +18 -3
  59. package/dist/vanilla/index.js +9 -9
  60. package/package.json +66 -44
  61. /package/dist/shared/{esm-b7xs9cde.js → esm-k7kedp3y.js} +0 -0
@@ -0,0 +1,134 @@
1
+ // src/server/ephemeral/memory.ts
2
+ var DEFAULT_MAX_ENTRIES = 1e4;
3
+ function indexKey(room, key, clientId) {
4
+ return `${room}\x00${key}\x00${clientId}`;
5
+ }
6
+ function parseIndexKey(packed) {
7
+ const [room, key, clientId] = packed.split("\x00");
8
+ return { room, key, clientId };
9
+ }
10
+
11
+ class EphemeralManager {
12
+ store = new Map;
13
+ clientIndex = new Map;
14
+ entryCount = 0;
15
+ maxEntries;
16
+ constructor(maxEntries) {
17
+ this.maxEntries = maxEntries ?? DEFAULT_MAX_ENTRIES;
18
+ }
19
+ set(room, key, clientId, userId, data, ttlMs) {
20
+ const roomMap = this.store.get(room) ?? new Map;
21
+ const keyMap = roomMap.get(key) ?? new Map;
22
+ const existing = keyMap.get(clientId);
23
+ if (!existing && this.entryCount >= this.maxEntries) {
24
+ return false;
25
+ }
26
+ const state = {
27
+ clientId,
28
+ userId,
29
+ key,
30
+ data,
31
+ updatedAt: Date.now(),
32
+ ttlMs
33
+ };
34
+ keyMap.set(clientId, state);
35
+ roomMap.set(key, keyMap);
36
+ this.store.set(room, roomMap);
37
+ if (!existing) {
38
+ this.entryCount++;
39
+ this.addToClientIndex(clientId, indexKey(room, key, clientId));
40
+ }
41
+ return true;
42
+ }
43
+ addToClientIndex(clientId, packed) {
44
+ const clientSet = this.clientIndex.get(clientId) ?? new Set;
45
+ clientSet.add(packed);
46
+ this.clientIndex.set(clientId, clientSet);
47
+ }
48
+ removeFromClientIndex(clientId, packed) {
49
+ const clientSet = this.clientIndex.get(clientId);
50
+ if (!clientSet)
51
+ return;
52
+ clientSet.delete(packed);
53
+ if (clientSet.size === 0)
54
+ this.clientIndex.delete(clientId);
55
+ }
56
+ get(room, key) {
57
+ const roomMap = this.store.get(room);
58
+ if (!roomMap)
59
+ return {};
60
+ const keyMap = roomMap.get(key);
61
+ if (!keyMap)
62
+ return {};
63
+ return Object.fromEntries(keyMap.entries());
64
+ }
65
+ getRoom(room) {
66
+ const roomMap = this.store.get(room);
67
+ if (!roomMap)
68
+ return {};
69
+ const out = {};
70
+ for (const [key, keyMap] of roomMap) {
71
+ out[key] = Object.fromEntries(keyMap.entries());
72
+ }
73
+ return out;
74
+ }
75
+ remove(room, key, clientId) {
76
+ const roomMap = this.store.get(room);
77
+ if (!roomMap)
78
+ return;
79
+ const keyMap = roomMap.get(key);
80
+ if (!keyMap)
81
+ return;
82
+ if (keyMap.has(clientId)) {
83
+ keyMap.delete(clientId);
84
+ this.entryCount--;
85
+ this.removeFromClientIndex(clientId, indexKey(room, key, clientId));
86
+ }
87
+ if (keyMap.size === 0) {
88
+ roomMap.delete(key);
89
+ }
90
+ if (roomMap.size === 0) {
91
+ this.store.delete(room);
92
+ }
93
+ }
94
+ removeClient(clientId) {
95
+ const indices = this.clientIndex.get(clientId);
96
+ if (!indices)
97
+ return;
98
+ const entries = [...indices];
99
+ for (const packed of entries) {
100
+ const { room, key, clientId: owner } = parseIndexKey(packed);
101
+ this.remove(room, key, owner);
102
+ }
103
+ this.clientIndex.delete(clientId);
104
+ }
105
+ cleanupExpired() {
106
+ const now = Date.now();
107
+ const toRemove = [];
108
+ for (const [room, roomMap] of this.store) {
109
+ for (const [key, keyMap] of roomMap) {
110
+ for (const [clientId, state] of keyMap) {
111
+ if (state.ttlMs && now - state.updatedAt > state.ttlMs) {
112
+ toRemove.push({ room, key, clientId });
113
+ }
114
+ }
115
+ }
116
+ }
117
+ for (const { room, key, clientId } of toRemove) {
118
+ this.remove(room, key, clientId);
119
+ }
120
+ }
121
+ size() {
122
+ return this.entryCount;
123
+ }
124
+ destroy() {
125
+ this.store.clear();
126
+ this.clientIndex.clear();
127
+ this.entryCount = 0;
128
+ }
129
+ }
130
+ function createMemoryEphemeral(maxEntries) {
131
+ return new EphemeralManager(maxEntries);
132
+ }
133
+
134
+ export { EphemeralManager, createMemoryEphemeral };
@@ -267,6 +267,17 @@ declare class ClientStore {
267
267
  clearTable(table: string): void;
268
268
  applySnapshot(table: string, rows: Record<string, unknown>[], colClocks: Record<string, Record<string, string>>, append?: boolean, pk?: string): void;
269
269
  applyDelta(table: string, op: string, rowId: string, payload: Record<string, unknown> | null, hlc: string, colClocks?: Record<string, string>): void;
270
+ /**
271
+ * Guarantee a materialized row carries its own primary key.
272
+ *
273
+ * A delta's payload is not always a whole row: eager broadcasts forward the
274
+ * writer's payload verbatim, and the typed API omits the pk from what a
275
+ * client may write — so an eagerly-broadcast insert describes a row with no
276
+ * id in it. Rows are addressed by `rowId` everywhere in the protocol, so the
277
+ * key is never in doubt; only the materialized object was missing it, and
278
+ * `rows.map(r => r.id)` came back undefined.
279
+ */
280
+ private withPk;
270
281
  revertOp(opId: string, serverRow: Record<string, unknown> | null | undefined): void;
271
282
  setTableMeta(meta: Record<string, {
272
283
  serverSet: string[];
@@ -496,11 +507,15 @@ interface DrizzleTableLike {
496
507
  /**
497
508
  * Value supplied per serverSet field in the schema's object form.
498
509
  * Either a static value or a function that receives the request context.
510
+ *
511
+ * The static arm is enumerated rather than written as `unknown`: a union with
512
+ * `unknown` collapses to `unknown`, which strips the contextual type from the
513
+ * callback arm and makes every `(ctx) => …` an implicit `any` under `strict`.
499
514
  */
500
- type ServerSetSchemaValue = unknown | ((ctx: {
515
+ type ServerSetSchemaValue = ((ctx: {
501
516
  auth: unknown;
502
517
  params: unknown;
503
- }) => unknown);
518
+ }) => unknown) | string | number | bigint | boolean | symbol | null | undefined | Date | readonly unknown[] | Record<string, unknown>;
504
519
  /**
505
520
  * Schema-side `serverSet` declaration. Two shapes:
506
521
  * - `string[]` — keys only; values are supplied at `implement(...)` time.
@@ -642,4 +657,4 @@ interface SyncSvelteHooks<TQueries extends SyncQueryMap> {
642
657
  createStore: (config: SyncStoreConfig) => TypedSyncStore<TQueries>;
643
658
  }
644
659
  declare function createSyncSvelte<TQueries extends SyncQueryMap>(): SyncSvelteHooks<TQueries>;
645
- export { createSyncSvelte, createSyncStore, createBrowserWsTransport, TypedSyncStore, SyncSvelteHooks, SyncStoreConfig, SyncStore, Readable };
660
+ export { Readable, SyncStore, SyncStoreConfig, SyncSvelteHooks, TypedSyncStore, createBrowserWsTransport, createSyncStore, createSyncSvelte };
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  SyncClient,
3
3
  pushSafely
4
- } from "../shared/esm-ytrd3hbq.js";
4
+ } from "../shared/esm-8qbr4y0d.js";
5
5
  import"../shared/esm-rw7jjtrv.js";
6
6
  import"../shared/esm-3tkwvysa.js";
7
- import"../shared/esm-b7xs9cde.js";
7
+ import"../shared/esm-k7kedp3y.js";
8
8
 
9
9
  // src/svelte/stores.ts
10
10
  function createBrowserWsTransport(url) {
@@ -166,21 +166,21 @@ function createSyncStore(config) {
166
166
  }
167
167
  }
168
168
  const unsub = client.subscribeEphemeral(cfg.key, (event) => {
169
- current = { ...current, [event.userId]: event.data };
169
+ current = { ...current, [event.clientId]: event.data };
170
170
  notifySubscribers();
171
171
  if (cfg.ttlMs) {
172
- const existing = timers.get(event.userId);
172
+ const existing = timers.get(event.clientId);
173
173
  if (existing) {
174
174
  clearTimeout(existing);
175
175
  }
176
176
  const timer = setTimeout(() => {
177
177
  const next = { ...current };
178
- delete next[event.userId];
178
+ delete next[event.clientId];
179
179
  current = next;
180
- timers.delete(event.userId);
180
+ timers.delete(event.clientId);
181
181
  notifySubscribers();
182
182
  }, cfg.ttlMs);
183
- timers.set(event.userId, timer);
183
+ timers.set(event.clientId, timer);
184
184
  }
185
185
  });
186
186
  const events = {
@@ -256,7 +256,7 @@ function createSyncSvelte() {
256
256
  return { createStore };
257
257
  }
258
258
  export {
259
- createSyncSvelte,
259
+ createBrowserWsTransport,
260
260
  createSyncStore,
261
- createBrowserWsTransport
261
+ createSyncSvelte
262
262
  };
@@ -212,4 +212,4 @@ declare function createBunWsServerTransport(cfg?: BunWsServerConfig): {
212
212
  pong?(ws: BunServerWebSocket<BunWsTransportData>): void;
213
213
  };
214
214
  };
215
- export { createBunWsServerTransport, BunWsTransportData, BunWsServerConfig };
215
+ export { BunWsServerConfig, BunWsTransportData, createBunWsServerTransport };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  TransportSendError
3
3
  } from "../shared/esm-3tkwvysa.js";
4
- import"../shared/esm-b7xs9cde.js";
4
+ import"../shared/esm-k7kedp3y.js";
5
5
 
6
6
  // src/transport/bun-ws.ts
7
7
  function trySend(clientId, ws, data, maxBufferedBytes) {
@@ -207,4 +207,4 @@ interface PollingClientConfig {
207
207
  headers?: Record<string, string>;
208
208
  }
209
209
  declare function createPollingClientTransport(config: PollingClientConfig): ClientTransport;
210
- export { pollingBodyTooLarge, createPollingServerTransport, createPollingClientTransport, PollingServerConfig, PollingClientConfig };
210
+ export { PollingClientConfig, PollingServerConfig, createPollingClientTransport, createPollingServerTransport, pollingBodyTooLarge };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  TransportSendError
3
3
  } from "../shared/esm-3tkwvysa.js";
4
- import"../shared/esm-b7xs9cde.js";
4
+ import"../shared/esm-k7kedp3y.js";
5
5
 
6
6
  // src/transport/polling.ts
7
7
  function pollingBodyTooLarge(body, limit = 1e6) {
@@ -175,7 +175,7 @@ function createPollingClientTransport(config) {
175
175
  };
176
176
  }
177
177
  export {
178
- pollingBodyTooLarge,
178
+ createPollingClientTransport,
179
179
  createPollingServerTransport,
180
- createPollingClientTransport
180
+ pollingBodyTooLarge
181
181
  };
@@ -202,4 +202,4 @@ interface SseClientConfig {
202
202
  headers?: Record<string, string>;
203
203
  }
204
204
  declare function createSseClientTransport(config: SseClientConfig): ClientTransport;
205
- export { createSseServerTransport, createSseClientTransport, SseServerConfig, SseClientConfig };
205
+ export { SseClientConfig, SseServerConfig, createSseClientTransport, createSseServerTransport };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  TransportSendError
3
3
  } from "../shared/esm-3tkwvysa.js";
4
- import"../shared/esm-b7xs9cde.js";
4
+ import"../shared/esm-k7kedp3y.js";
5
5
 
6
6
  // src/transport/sse.ts
7
7
  function createSseServerTransport(cfg = {}) {
@@ -203,6 +203,6 @@ function createSseClientTransport(config) {
203
203
  };
204
204
  }
205
205
  export {
206
- createSseServerTransport,
207
- createSseClientTransport
206
+ createSseClientTransport,
207
+ createSseServerTransport
208
208
  };
@@ -233,4 +233,4 @@ interface WebSocketLike {
233
233
  /** Bytes queued but not yet flushed. Used for outbound backpressure. */
234
234
  bufferedAmount?: number;
235
235
  }
236
- export { isOriginAllowed, createWsServerTransport, createWsClientTransport, WsServerTransportConfig, WsServerConfig, WsClientConfig, WebSocketLike };
236
+ export { WebSocketLike, WsClientConfig, WsServerConfig, WsServerTransportConfig, createWsClientTransport, createWsServerTransport, isOriginAllowed };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  TransportSendError
3
3
  } from "../shared/esm-3tkwvysa.js";
4
- import"../shared/esm-b7xs9cde.js";
4
+ import"../shared/esm-k7kedp3y.js";
5
5
 
6
6
  // src/transport/ws.ts
7
7
  function trySend(clientId, ws, data, maxBufferedBytes) {
@@ -220,7 +220,7 @@ function createWsClientTransport(config) {
220
220
  };
221
221
  }
222
222
  export {
223
- isOriginAllowed,
223
+ createWsClientTransport,
224
224
  createWsServerTransport,
225
- createWsClientTransport
225
+ isOriginAllowed
226
226
  };
@@ -267,6 +267,17 @@ declare class ClientStore {
267
267
  clearTable(table: string): void;
268
268
  applySnapshot(table: string, rows: Record<string, unknown>[], colClocks: Record<string, Record<string, string>>, append?: boolean, pk?: string): void;
269
269
  applyDelta(table: string, op: string, rowId: string, payload: Record<string, unknown> | null, hlc: string, colClocks?: Record<string, string>): void;
270
+ /**
271
+ * Guarantee a materialized row carries its own primary key.
272
+ *
273
+ * A delta's payload is not always a whole row: eager broadcasts forward the
274
+ * writer's payload verbatim, and the typed API omits the pk from what a
275
+ * client may write — so an eagerly-broadcast insert describes a row with no
276
+ * id in it. Rows are addressed by `rowId` everywhere in the protocol, so the
277
+ * key is never in doubt; only the materialized object was missing it, and
278
+ * `rows.map(r => r.id)` came back undefined.
279
+ */
280
+ private withPk;
270
281
  revertOp(opId: string, serverRow: Record<string, unknown> | null | undefined): void;
271
282
  setTableMeta(meta: Record<string, {
272
283
  serverSet: string[];
@@ -504,11 +515,15 @@ interface DrizzleTableLike {
504
515
  /**
505
516
  * Value supplied per serverSet field in the schema's object form.
506
517
  * Either a static value or a function that receives the request context.
518
+ *
519
+ * The static arm is enumerated rather than written as `unknown`: a union with
520
+ * `unknown` collapses to `unknown`, which strips the contextual type from the
521
+ * callback arm and makes every `(ctx) => …` an implicit `any` under `strict`.
507
522
  */
508
- type ServerSetSchemaValue = unknown | ((ctx: {
523
+ type ServerSetSchemaValue = ((ctx: {
509
524
  auth: unknown;
510
525
  params: unknown;
511
- }) => unknown);
526
+ }) => unknown) | string | number | bigint | boolean | symbol | null | undefined | Date | readonly unknown[] | Record<string, unknown>;
512
527
  /**
513
528
  * Schema-side `serverSet` declaration. Two shapes:
514
529
  * - `string[]` — keys only; values are supplied at `implement(...)` time.
@@ -654,4 +669,4 @@ interface SyncVanillaHooks<TQueries extends SyncQueryMap> {
654
669
  createSync: (config: VanillaSyncConfig) => TypedVanillaSync<TQueries>;
655
670
  }
656
671
  declare function createSyncVanilla<TQueries extends SyncQueryMap>(): SyncVanillaHooks<TQueries>;
657
- export { createSyncVanilla, createSync2 as createSync, createBrowserWsTransport, VanillaSyncConfig, VanillaSync, TypedVanillaSync, TableBinding, SyncVanillaHooks, EphemeralBinding };
672
+ export { EphemeralBinding, SyncVanillaHooks, TableBinding, TypedVanillaSync, VanillaSync, VanillaSyncConfig, createBrowserWsTransport, createSync2 as createSync, createSyncVanilla };
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  SyncClient,
3
3
  pushSafely
4
- } from "../shared/esm-ytrd3hbq.js";
4
+ } from "../shared/esm-8qbr4y0d.js";
5
5
  import"../shared/esm-rw7jjtrv.js";
6
6
  import"../shared/esm-3tkwvysa.js";
7
- import"../shared/esm-b7xs9cde.js";
7
+ import"../shared/esm-k7kedp3y.js";
8
8
 
9
9
  // src/vanilla/sync.ts
10
10
  function createBrowserWsTransport(url) {
@@ -184,20 +184,20 @@ function createSync(config) {
184
184
  }
185
185
  }
186
186
  const unsub = client.subscribeEphemeral(ephConfig.key, (event) => {
187
- events = { ...events, [event.userId]: event.data };
187
+ events = { ...events, [event.clientId]: event.data };
188
188
  if (ephConfig.ttlMs) {
189
- const existing = timers.get(event.userId);
189
+ const existing = timers.get(event.clientId);
190
190
  if (existing) {
191
191
  clearTimeout(existing);
192
192
  }
193
193
  const timer = setTimeout(() => {
194
194
  const next = { ...events };
195
- delete next[event.userId];
195
+ delete next[event.clientId];
196
196
  events = next;
197
- timers.delete(event.userId);
197
+ timers.delete(event.clientId);
198
198
  notifyChange();
199
199
  }, ephConfig.ttlMs);
200
- timers.set(event.userId, timer);
200
+ timers.set(event.clientId, timer);
201
201
  }
202
202
  notifyChange();
203
203
  });
@@ -272,7 +272,7 @@ function createSyncVanilla() {
272
272
  };
273
273
  }
274
274
  export {
275
- createSyncVanilla,
275
+ createBrowserWsTransport,
276
276
  createSync,
277
- createBrowserWsTransport
277
+ createSyncVanilla
278
278
  };
package/package.json CHANGED
@@ -1,70 +1,63 @@
1
1
  {
2
2
  "name": "reflectdb",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Real-time sync engine for TypeScript — a server database and offline-first browser clients stay in sync, with optimistic writes and typed queries.",
5
5
  "keywords": [
6
- "sync",
7
- "sync-engine",
8
- "sync-server",
9
- "data-sync",
10
- "state-sync",
11
- "real-time",
12
- "realtime",
13
- "replication",
14
- "live-query",
15
- "local-first",
16
- "offline-first",
17
- "offline",
18
- "optimistic-updates",
6
+ "bun",
7
+ "collaborative",
8
+ "collaborative-editing",
19
9
  "conflict-resolution",
20
- "last-write-wins",
10
+ "data-sync",
11
+ "drizzle",
12
+ "drizzle-orm",
21
13
  "eventual-consistency",
22
- "hybrid-logical-clock",
23
14
  "hlc",
24
- "op-log",
25
- "websocket",
26
- "sse",
27
- "server-sent-events",
15
+ "hybrid-logical-clock",
16
+ "indexeddb",
17
+ "kysely",
18
+ "last-write-wins",
19
+ "live-query",
20
+ "local-first",
28
21
  "long-polling",
29
22
  "multiplayer",
30
- "collaborative",
31
- "collaborative-editing",
23
+ "offline",
24
+ "offline-first",
25
+ "op-log",
26
+ "optimistic-updates",
27
+ "postgres",
32
28
  "presence",
33
- "typescript",
34
- "type-safe",
35
29
  "react",
36
30
  "react-hooks",
37
- "svelte",
38
- "drizzle",
39
- "drizzle-orm",
40
- "kysely",
41
- "indexeddb",
42
- "postgres",
31
+ "real-time",
32
+ "realtime",
33
+ "replication",
34
+ "server-sent-events",
43
35
  "sqlite",
44
- "bun"
36
+ "sse",
37
+ "state-sync",
38
+ "svelte",
39
+ "sync",
40
+ "sync-engine",
41
+ "sync-server",
42
+ "type-safe",
43
+ "typescript",
44
+ "websocket"
45
45
  ],
46
46
  "homepage": "https://github.com/TimMikeladze/reflectdb#readme",
47
47
  "bugs": {
48
48
  "url": "https://github.com/TimMikeladze/reflectdb/issues"
49
49
  },
50
+ "license": "MIT",
51
+ "author": "Tim Mikeladze <tim.mikeladze@gmail.com> (https://github.com/TimMikeladze)",
50
52
  "repository": {
51
53
  "type": "git",
52
54
  "url": "git+https://github.com/TimMikeladze/reflectdb.git"
53
55
  },
54
56
  "funding": "https://github.com/sponsors/TimMikeladze",
55
- "license": "MIT",
56
- "author": "Tim Mikeladze <tim.mikeladze@gmail.com> (https://github.com/TimMikeladze)",
57
- "type": "module",
58
- "sideEffects": false,
59
- "engines": {
60
- "node": ">=22"
61
- },
62
57
  "files": [
63
58
  "dist"
64
59
  ],
65
- "publishConfig": {
66
- "access": "public"
67
- },
60
+ "type": "module",
68
61
  "main": "./dist/cjs/core/index.cjs",
69
62
  "module": "./dist/core/index.js",
70
63
  "types": "./dist/core/index.d.ts",
@@ -199,25 +192,50 @@
199
192
  "default": "./dist/cjs/client/storage/indexeddb.cjs"
200
193
  }
201
194
  },
195
+ "./server/ephemeral": {
196
+ "import": {
197
+ "types": "./dist/server/ephemeral/index.d.ts",
198
+ "default": "./dist/server/ephemeral/index.js"
199
+ },
200
+ "require": {
201
+ "types": "./dist/cjs/server/ephemeral/index.d.cts",
202
+ "default": "./dist/cjs/server/ephemeral/index.cjs"
203
+ }
204
+ },
205
+ "./server/ephemeral/redis": {
206
+ "import": {
207
+ "types": "./dist/server/ephemeral/redis.d.ts",
208
+ "default": "./dist/server/ephemeral/redis.js"
209
+ },
210
+ "require": {
211
+ "types": "./dist/cjs/server/ephemeral/redis.d.cts",
212
+ "default": "./dist/cjs/server/ephemeral/redis.cjs"
213
+ }
214
+ },
202
215
  "./package.json": "./package.json"
203
216
  },
217
+ "publishConfig": {
218
+ "access": "public"
219
+ },
204
220
  "scripts": {
205
- "build": "bunup --filter esm && bunup --filter cjs",
221
+ "build": "NODE_ENV=production bunup --filter esm && NODE_ENV=production bunup --filter cjs && bun run verify:jsx",
206
222
  "format": "oxfmt",
207
223
  "lint": "oxlint",
208
224
  "prepare": "bun simple-git-hooks",
209
225
  "release": "bumpp --commit --push --tag",
210
226
  "test": "bun test",
211
227
  "test:coverage": "bun test --coverage",
212
- "test:watch": "bun test --watch",
213
- "test:ui": "bun test/ui/server.tsx",
214
228
  "test:sync": "bun test/ui/test-sync.ts",
229
+ "test:ui": "bun test/ui/server.tsx",
230
+ "test:watch": "bun test --watch",
215
231
  "type-check": "tsc --noEmit",
216
232
  "verify:exports": "bun scripts/verify-exports.ts",
233
+ "verify:jsx": "bun scripts/verify-jsx.ts",
217
234
  "verify:node": "bun scripts/verify-node-consumer.ts"
218
235
  },
219
236
  "devDependencies": {
220
237
  "@types/bun": "^1.3.10",
238
+ "@types/pg": "^8.21.0",
221
239
  "@types/react": "^19.2.14",
222
240
  "@types/react-dom": "^19.2.3",
223
241
  "bumpp": "^10.4.1",
@@ -227,6 +245,7 @@
227
245
  "kysely": "^0.28.12",
228
246
  "oxfmt": "^0.36.0",
229
247
  "oxlint": "^1.51.0",
248
+ "pg": "^8.23.0",
230
249
  "react-dom": "^19.2.4",
231
250
  "simple-git-hooks": "^2.13.1",
232
251
  "typescript": "^5.9.3"
@@ -249,5 +268,8 @@
249
268
  },
250
269
  "simple-git-hooks": {
251
270
  "pre-commit": "bun run lint && bun run type-check"
271
+ },
272
+ "engines": {
273
+ "node": ">=22"
252
274
  }
253
275
  }