@signaldb/core 2.0.0-beta.2 → 2.0.0-beta.21

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 (145) hide show
  1. package/dist/.vite/manifest.json +183 -80
  2. package/dist/AsyncDataAdapter.d.ts +53 -7
  3. package/dist/AutoFetchDataAdapter.d.ts +4 -6
  4. package/dist/Collection/Cursor.d.ts +56 -4
  5. package/dist/Collection/Observer.d.ts +33 -0
  6. package/dist/Collection/index.d.ts +66 -19
  7. package/dist/Collection/types.d.ts +9 -2
  8. package/dist/DataAdapter.d.ts +24 -6
  9. package/dist/DefaultDataAdapter.d.ts +5 -5
  10. package/dist/WorkerDataAdapter.d.ts +57 -5
  11. package/dist/WorkerDataAdapterHost.d.ts +9 -7
  12. package/dist/createIndex.d.ts +2 -2
  13. package/dist/createIndexProvider.d.ts +2 -2
  14. package/dist/createReactivityAdapter.d.ts +2 -2
  15. package/dist/createStorageAdapter.d.ts +1 -1
  16. package/dist/getIndexInfo.d.ts +3 -4
  17. package/dist/index.cjs.js +33 -31
  18. package/dist/index.d.ts +6 -1
  19. package/dist/index.mjs +17 -32
  20. package/dist/index10.cjs.js +11 -0
  21. package/dist/index10.mjs +10 -18
  22. package/dist/index11.cjs.js +23 -0
  23. package/dist/index11.mjs +22 -15
  24. package/dist/index12.cjs.js +45 -0
  25. package/dist/index12.mjs +44 -353
  26. package/dist/index13.cjs.js +22 -0
  27. package/dist/index13.mjs +21 -419
  28. package/dist/index14.cjs.js +45 -0
  29. package/dist/index14.mjs +44 -206
  30. package/dist/index15.cjs.js +86 -0
  31. package/dist/index15.mjs +85 -388
  32. package/dist/index16.cjs.js +15 -0
  33. package/dist/index16.mjs +14 -579
  34. package/dist/index17.cjs.js +141 -0
  35. package/dist/index17.mjs +140 -152
  36. package/dist/index18.cjs.js +47 -0
  37. package/dist/index18.mjs +46 -26
  38. package/dist/index19.cjs.js +15 -0
  39. package/dist/index19.mjs +14 -41
  40. package/dist/index2.cjs.js +33 -0
  41. package/dist/index2.mjs +32 -258
  42. package/dist/index20.cjs.js +23 -0
  43. package/dist/index20.mjs +22 -16
  44. package/dist/index21.cjs.js +37 -0
  45. package/dist/index21.mjs +36 -104
  46. package/dist/index22.cjs.js +35 -0
  47. package/dist/index22.mjs +34 -128
  48. package/dist/index23.cjs.js +21 -0
  49. package/dist/index23.mjs +20 -7
  50. package/dist/index24.cjs.js +19 -0
  51. package/dist/index24.mjs +18 -27
  52. package/dist/index25.cjs.js +157 -0
  53. package/dist/index25.mjs +156 -11
  54. package/dist/index26.cjs.js +38 -0
  55. package/dist/index26.mjs +37 -29
  56. package/dist/index27.cjs.js +42 -0
  57. package/dist/index27.mjs +41 -46
  58. package/dist/index28.cjs.js +347 -0
  59. package/dist/index28.mjs +345 -7
  60. package/dist/index29.cjs.js +602 -0
  61. package/dist/index29.mjs +601 -7
  62. package/dist/index3.cjs.js +19 -0
  63. package/dist/index3.mjs +18 -556
  64. package/dist/index30.cjs.js +11 -0
  65. package/dist/index30.mjs +10 -42
  66. package/dist/index31.cjs.js +11 -0
  67. package/dist/index31.mjs +10 -29
  68. package/dist/index32.cjs.js +90 -0
  69. package/dist/index32.mjs +89 -10
  70. package/dist/index33.cjs.js +53 -0
  71. package/dist/index33.mjs +52 -5
  72. package/dist/index34.cjs.js +453 -0
  73. package/dist/index34.mjs +453 -0
  74. package/dist/index35.cjs.js +72 -0
  75. package/dist/index35.mjs +72 -0
  76. package/dist/index36.cjs.js +580 -0
  77. package/dist/index36.mjs +580 -0
  78. package/dist/index37.cjs.js +21 -0
  79. package/dist/index37.mjs +21 -0
  80. package/dist/index38.cjs.js +363 -0
  81. package/dist/index38.mjs +363 -0
  82. package/dist/index39.cjs.js +513 -0
  83. package/dist/index39.mjs +513 -0
  84. package/dist/index4.cjs.js +209 -0
  85. package/dist/index4.mjs +204 -5
  86. package/dist/index5.cjs.js +187 -0
  87. package/dist/index5.mjs +186 -5
  88. package/dist/index6.cjs.js +303 -0
  89. package/dist/index6.mjs +301 -28
  90. package/dist/index7.cjs.js +125 -0
  91. package/dist/index7.mjs +124 -12
  92. package/dist/index8.cjs.js +33 -0
  93. package/dist/index8.mjs +32 -5
  94. package/dist/index9.cjs.js +12 -0
  95. package/dist/index9.mjs +11 -133
  96. package/dist/types/IndexProvider.d.ts +2 -2
  97. package/dist/types/Modifier.d.ts +1 -1
  98. package/dist/types/ReactivityAdapter.d.ts +1 -1
  99. package/dist/types/StorageAdapter.d.ts +9 -1
  100. package/dist/utils/applyQueryOptions.d.ts +15 -0
  101. package/dist/utils/createSignal.d.ts +2 -2
  102. package/dist/utils/getMatchingKeys.d.ts +2 -2
  103. package/dist/utils/idIndexQuery.d.ts +20 -0
  104. package/dist/utils/incrementalQueryUpdate.d.ts +62 -0
  105. package/dist/utils/isFieldExpression.d.ts +1 -1
  106. package/dist/utils/match.d.ts +1 -1
  107. package/dist/utils/modify.d.ts +1 -1
  108. package/dist/utils/projectItems.d.ts +12 -0
  109. package/dist/utils/queryDelta.d.ts +83 -0
  110. package/dist/utils/queryId.d.ts +2 -2
  111. package/dist/utils/reactiveOrAsync.d.ts +59 -0
  112. package/dist/utils/storageIndexQuery.d.ts +20 -0
  113. package/package.json +1 -1
  114. package/dist/index.cjs10.js +0 -18
  115. package/dist/index.cjs11.js +0 -15
  116. package/dist/index.cjs12.js +0 -353
  117. package/dist/index.cjs13.js +0 -419
  118. package/dist/index.cjs14.js +0 -206
  119. package/dist/index.cjs15.js +0 -388
  120. package/dist/index.cjs16.js +0 -579
  121. package/dist/index.cjs17.js +0 -152
  122. package/dist/index.cjs18.js +0 -26
  123. package/dist/index.cjs19.js +0 -42
  124. package/dist/index.cjs2.js +0 -259
  125. package/dist/index.cjs20.js +0 -16
  126. package/dist/index.cjs21.js +0 -104
  127. package/dist/index.cjs22.js +0 -129
  128. package/dist/index.cjs23.js +0 -7
  129. package/dist/index.cjs24.js +0 -27
  130. package/dist/index.cjs25.js +0 -10
  131. package/dist/index.cjs26.js +0 -29
  132. package/dist/index.cjs27.js +0 -46
  133. package/dist/index.cjs28.js +0 -8
  134. package/dist/index.cjs29.js +0 -7
  135. package/dist/index.cjs3.js +0 -557
  136. package/dist/index.cjs30.js +0 -42
  137. package/dist/index.cjs31.js +0 -29
  138. package/dist/index.cjs32.js +0 -9
  139. package/dist/index.cjs33.js +0 -5
  140. package/dist/index.cjs4.js +0 -5
  141. package/dist/index.cjs5.js +0 -5
  142. package/dist/index.cjs6.js +0 -29
  143. package/dist/index.cjs7.js +0 -12
  144. package/dist/index.cjs8.js +0 -5
  145. package/dist/index.cjs9.js +0 -133
package/dist/index9.mjs CHANGED
@@ -1,134 +1,12 @@
1
- class EventEmitter {
2
- _maxListeners = 100;
3
- /**
4
- * We store a set of the listeners for each event.
5
- */
6
- _listenerStore = /* @__PURE__ */ new Map();
7
- setMaxListeners(max) {
8
- this._maxListeners = max;
9
- return this;
10
- }
11
- /**
12
- * Subscribe to an event with a listener function.
13
- * @param eventName The event name (key of E).
14
- * @param listener A function that receives the emitted arguments.
15
- * @returns The emitter instance (for chaining).
16
- */
17
- on(eventName, listener) {
18
- let listenersSet = this._listenerStore.get(eventName);
19
- if (!listenersSet) {
20
- listenersSet = /* @__PURE__ */ new Set();
21
- this._listenerStore.set(eventName, listenersSet);
22
- }
23
- listenersSet.add(listener);
24
- if (listenersSet.size > this._maxListeners) {
25
- console.warn(`Possible EventEmitter memory leak detected. ${listenersSet.size} ${String(eventName)} listeners added. Use emitter.setMaxListeners() to increase limit.`);
26
- }
27
- return this;
28
- }
29
- /**
30
- * Subscribe to an event with a listener function.
31
- * @param eventName The event name (key of E).
32
- * @param listener A function that receives the emitted arguments.
33
- * @returns The emitter instance (for chaining).
34
- */
35
- addListener(eventName, listener) {
36
- return this.on(eventName, listener);
37
- }
38
- /**
39
- * Subscribe to an event, handling it only once. Automatically removes
40
- * the listener after it fires the first time.
41
- * @param eventName The event name (key of E).
42
- * @param listener A function that receives the emitted arguments.
43
- * @returns The emitter instance (for chaining).
44
- */
45
- once(eventName, listener) {
46
- const onceWrapper = ((...args) => {
47
- listener(...args);
48
- this.off(eventName, onceWrapper);
49
- });
50
- return this.on(eventName, onceWrapper);
51
- }
52
- /**
53
- * Unsubscribe a previously subscribed listener.
54
- * @param eventName The event name (key of E).
55
- * @param listener The original function passed to `on` or `once`.
56
- * @returns The emitter instance (for chaining).
57
- */
58
- off(eventName, listener) {
59
- const listenersSet = this._listenerStore.get(eventName);
60
- if (!listenersSet)
61
- return this;
62
- listenersSet.delete(listener);
63
- if (listenersSet.size === 0) {
64
- this._listenerStore.delete(eventName);
65
- }
66
- return this;
67
- }
68
- /**
69
- * Unsubscribe a previously subscribed listener.
70
- * @param eventName The event name (key of E).
71
- * @param listener The original function passed to `on` or `once`.
72
- * @returns The emitter instance (for chaining).
73
- */
74
- removeListener(eventName, listener) {
75
- return this.off(eventName, listener);
76
- }
77
- /**
78
- * Emit (dispatch) an event with a variable number of arguments.
79
- * @param eventName The event name (key of E).
80
- * @param args The arguments to pass to subscribed listeners.
81
- */
82
- emit(eventName, ...args) {
83
- this.listeners(eventName).forEach((listener) => {
84
- listener(...args);
85
- });
86
- }
87
- /**
88
- * Returns the array of listener functions currently registered for a given event.
89
- * @param eventName The event name (key of E).
90
- * @returns An array of listener functions.
91
- */
92
- listeners(eventName) {
93
- const listenersSet = this._listenerStore.get(eventName);
94
- if (!listenersSet)
95
- return [];
96
- return [...listenersSet.values()];
97
- }
98
- /**
99
- * Returns the number of listeners for a given event.
100
- * @param eventName The event name (key of E).
101
- * @returns The number of listeners.
102
- */
103
- listenerCount(eventName) {
104
- const listenersSet = this._listenerStore.get(eventName);
105
- return listenersSet ? listenersSet.size : 0;
106
- }
107
- /**
108
- * Removes all listeners for a given event, or all events if none is specified.
109
- * @param eventName Optional. If omitted, clears all events’ listeners.
110
- * @returns The emitter instance (for chaining).
111
- */
112
- removeAllListeners(eventName) {
113
- if (eventName === void 0) {
114
- for (const [eventName_, listenersSet] of this._listenerStore.entries()) {
115
- for (const listener of listenersSet.values()) {
116
- this.off(eventName_, listener);
117
- }
118
- }
119
- this._listenerStore.clear();
120
- } else {
121
- const listenersSet = this._listenerStore.get(eventName);
122
- if (listenersSet) {
123
- for (const listener of listenersSet.values()) {
124
- this.off(eventName, listener);
125
- }
126
- this._listenerStore.delete(eventName);
127
- }
128
- }
129
- return this;
130
- }
1
+ //#region src/utils/randomId.ts
2
+ /**
3
+ * creates a random id
4
+ * @returns a random string of 16 characters
5
+ * @example
6
+ * randomId() // '1234567890abcdef'
7
+ */
8
+ function randomId() {
9
+ return Array.from({ length: 16 }, () => "abcdefghijklmnopqrstuvwxyz0123456789"[Math.floor(Math.random() * 36)]).join("");
131
10
  }
132
- export {
133
- EventEmitter as default
134
- };
11
+ //#endregion
12
+ export { randomId as default };
@@ -1,5 +1,5 @@
1
- import type { BaseItem } from '../Collection';
2
- import type { FlatSelector } from './Selector';
1
+ import { BaseItem } from '../Collection';
2
+ import { FlatSelector } from './Selector';
3
3
  export type IndexResult<IdType> = {
4
4
  ids: IdType[];
5
5
  fields: string[];
@@ -1,4 +1,4 @@
1
- import type { DotNotation, GetType } from './Selector';
1
+ import { DotNotation, GetType } from './Selector';
2
2
  type Dictionary<T> = Record<string, T>;
3
3
  type PartialMapTo<T, M> = Partial<Record<DotNotation<T>, M>> & Dictionary<M>;
4
4
  type OnlyElementsOfArrays<T> = T extends any[] ? Partial<T[0]> : never;
@@ -1,4 +1,4 @@
1
- import type Dependency from './Dependency';
1
+ import { default as Dependency } from './Dependency';
2
2
  export default interface ReactivityAdapter<T extends Dependency = Dependency> {
3
3
  create(): T;
4
4
  onDispose?(callback: () => void, Dependency: T): void;
@@ -12,7 +12,15 @@ export default interface StorageAdapter<T extends {
12
12
  readIds(positions: I[]): Promise<T[]>;
13
13
  createIndex(field: string): Promise<void>;
14
14
  dropIndex(field: string): Promise<void>;
15
- readIndex(field: string): Promise<Map<any, Set<I>>>;
15
+ /**
16
+ * The index, keyed by `serializeValue(value)` — not by the raw field value.
17
+ *
18
+ * SignalDB looks an index up with the serialized form, because that is what
19
+ * makes `3`, `'3'` and `new Date(...)` comparable as map keys at all. An
20
+ * adapter that stores its backend's own keys instead answers nothing for
21
+ * every non-string field, and everything for a `$ne` on one.
22
+ */
23
+ readIndex(field: string): Promise<Map<string | null, Set<I>>>;
16
24
  insert(items: T[]): Promise<void>;
17
25
  replace(items: T[]): Promise<void>;
18
26
  remove(items: T[]): Promise<void>;
@@ -0,0 +1,15 @@
1
+ import { QueryOptions } from '../DataAdapter';
2
+ import { default as Selector } from '../types/Selector';
3
+ import { BaseItem } from '../Collection/types';
4
+ /**
5
+ * Filters, sorts, paginates and projects a plain in-memory array the same way
6
+ * DefaultDataAdapter and WorkerDataAdapterHost apply a selector/QueryOptions
7
+ * pair to their stored items. Used to re-derive a query's result locally after
8
+ * a write, without asking the backing store again.
9
+ * @template T - The type of the items.
10
+ * @param items - The items to filter, sort, paginate and project.
11
+ * @param selector - The selector to match items against.
12
+ * @param options - Sort, skip, limit and field projection options.
13
+ * @returns The resulting items.
14
+ */
15
+ export default function applyQueryOptions<T extends BaseItem>(items: T[], selector: Selector<T>, options?: QueryOptions<T>): T[];
@@ -1,5 +1,5 @@
1
- import type ReactivityAdapter from '../types/ReactivityAdapter';
2
- import type Signal from '../types/Signal';
1
+ import { default as ReactivityAdapter } from '../types/ReactivityAdapter';
2
+ import { default as Signal } from '../types/Signal';
3
3
  /**
4
4
  * Creates a reactive signal for managing state and triggering dependencies.
5
5
  * The signal holds a value and provides methods to get and set the value,
@@ -1,5 +1,5 @@
1
- import type { BaseItem } from '../Collection/types';
2
- import type { FlatSelector } from '../types/Selector';
1
+ import { BaseItem } from '../Collection/types';
2
+ import { FlatSelector } from '../types/Selector';
3
3
  type KeyResult = {
4
4
  include: (string | null)[] | null;
5
5
  exclude: (string | null)[] | null;
@@ -0,0 +1,20 @@
1
+ import { BaseItem } from '../Collection/types';
2
+ import { IndexResult } from '../types/IndexProvider';
3
+ import { FlatSelector } from '../types/Selector';
4
+ /**
5
+ * Resolves a selector on `id` into the ids it names, without consulting an index.
6
+ *
7
+ * `id` is the one field every storage adapter can look up directly — that is what
8
+ * `readIds` is — so a query on it never needs an index to be declared and never
9
+ * needs the whole collection to be read. This behaves like an index provider that
10
+ * happens to need no stored index, because the ids are already in the selector.
11
+ *
12
+ * Only inclusive forms can be answered this way. `$ne`/`$nin` describe everything
13
+ * except* something, which cannot be enumerated without knowing every id, so they
14
+ * report no match and take the ordinary path.
15
+ * @template T - The type of the items in the collection.
16
+ * @template I - The type of the unique identifier for the items.
17
+ * @param selector - The flat selector to resolve.
18
+ * @returns An index result naming the matched ids, or `{ matched: false }`.
19
+ */
20
+ export default function idIndexQuery<T extends BaseItem<I> = BaseItem, I = any>(selector: FlatSelector<T>): IndexResult<I>;
@@ -0,0 +1,62 @@
1
+ import { QueryOptions } from '../DataAdapter';
2
+ import { BaseItem } from '../Collection/types';
3
+ import { default as Selector } from '../types/Selector';
4
+ /**
5
+ * The items a write created, updated or removed, from the point of view of a store.
6
+ *
7
+ * `upserts` are the *current* state of every item that still exists; `deletes` are the ids of items
8
+ * that no longer do. A write that changes an item's id contributes to both. Callers are responsible
9
+ * for that split — an "affected items" list holding an item's state from before and after a write
10
+ * cannot be told apart from two unrelated items here.
11
+ */
12
+ export interface QueryChangeset<T extends BaseItem> {
13
+ upserts: T[];
14
+ deletes: any[];
15
+ }
16
+ /**
17
+ * Recomputes a query's result from its previous result and the change that was just written,
18
+ * without going back to the store.
19
+ *
20
+ * A store re-executing the query instead reads every item it holds (or every item an index points
21
+ * at) and filters, sorts and projects the lot — for a write that touched one row. This does the
22
+ * same job in the size of the write, which is what a query's result costs to keep up to date when
23
+ * the change that affects it is already in hand.
24
+ *
25
+ * Returns `null` when the previous result is not enough to answer, and the caller has to re-execute
26
+ * the query after all:
27
+ * - `limit` or `skip`: the result is a window onto a larger set, and an item leaving the window has
28
+ * to be replaced by one the previous result never contained.
29
+ * - `fields` together with a `sort` the projection does not keep: the previous items are
30
+ * projected, so a sort key the projection dropped is no longer there to sort by. A projection
31
+ * that keeps every sort key is fine, and is the common case — a list sorted by the same date it
32
+ * displays.
33
+ * - a `null` selector, which matches nothing and is not worth a special case.
34
+ * @template T - The type of the items.
35
+ * @param previous - The query's previous result.
36
+ * @param selector - The query's selector.
37
+ * @param options - The query's options.
38
+ * @param changes - The items the write created, updated or removed.
39
+ * @returns The new result, or `null` when the query has to be re-executed.
40
+ */
41
+ export default function incrementalQueryUpdate<T extends BaseItem>(previous: T[], selector: Selector<T>, options: QueryOptions<T> | undefined, changes: QueryChangeset<T>): T[] | null;
42
+ /**
43
+ * Folds a change into a query's result, whatever the query's options.
44
+ *
45
+ * The unguarded version of `incrementalQueryUpdate`, for the places where the alternative is not a
46
+ * more accurate answer but a wrong one — layering a write that has not been confirmed yet on top of
47
+ * the last confirmed result, say. For a query returning everything it matches, this is exact. For a
48
+ * window onto a larger set it is the closest the window itself can get: an item that no longer
49
+ * belongs is dropped, one that does is placed, and the window is trimmed back to its length — but
50
+ * an item pulled in from beyond the window is not something the window knows about.
51
+ *
52
+ * What it never does is re-examine the items already in the result. They matched when the store
53
+ * produced them, they still match, and asking again is both wasteful and — for a projected result,
54
+ * whose items no longer carry the fields the selector names — wrong.
55
+ * @template T - The type of the items.
56
+ * @param previous - The query's previous result.
57
+ * @param selector - The query's selector.
58
+ * @param options - The query's options.
59
+ * @param changes - The items the write created, updated or removed.
60
+ * @returns The resulting items.
61
+ */
62
+ export declare function mergeChangesetIntoResult<T extends BaseItem>(previous: T[], selector: Selector<T>, options: QueryOptions<T> | undefined, changes: QueryChangeset<T>): T[];
@@ -1,4 +1,4 @@
1
- import type { FieldExpression } from '../types/Selector';
1
+ import { FieldExpression } from '../types/Selector';
2
2
  /**
3
3
  * Determines whether a given object is a valid field expression.
4
4
  * A field expression is an object containing query operators supported by MongoDB-style queries.
@@ -1,4 +1,4 @@
1
- import type Selector from '../types/Selector';
1
+ import { default as Selector } from '../types/Selector';
2
2
  type BaseItem = Record<string, any>;
3
3
  /**
4
4
  * Tests whether a given item matches a specified selector.
@@ -1,4 +1,4 @@
1
- import type Modifier from '../types/Modifier';
1
+ import { default as Modifier } from '../types/Modifier';
2
2
  /**
3
3
  * Applies a modifier to an object and returns a new modified object.
4
4
  * @template T - The type of the object to be modified.
@@ -0,0 +1,12 @@
1
+ import { QueryOptions } from '../DataAdapter';
2
+ import { BaseItem } from '../Collection/types';
3
+ /**
4
+ * Applies a query's field projection to a list of items, keeping the primary key unless the
5
+ * projection excludes it outright. Returns the items untouched when there is no projection, so a
6
+ * caller does not have to check for one first.
7
+ * @template T - The type of the items.
8
+ * @param items - The items to project.
9
+ * @param fields - The projection, or `undefined` for none.
10
+ * @returns The projected items.
11
+ */
12
+ export default function projectItems<T extends BaseItem>(items: T[], fields: QueryOptions<T>['fields']): T[];
@@ -0,0 +1,83 @@
1
+ import { BaseItem } from '../Collection/types';
2
+ /**
3
+ * The change between two consecutive results of the same query, expressed so it can be applied to
4
+ * the earlier result to obtain the later one.
5
+ *
6
+ * Indices in `added` and `moved` are positions in the *resulting* array and are always ascending,
7
+ * which is what makes applying them a matter of splicing in order. Removals and moves name items by
8
+ * id only: whoever applies the delta still holds the previous result and can look the item up
9
+ * there, so there is no reason to send it twice — the point of the whole exercise is that a change
10
+ * costs the size of the change, not the size of the result.
11
+ */
12
+ export interface QueryDelta<T extends BaseItem = BaseItem> {
13
+ /** Items that were not in the previous result, at their position in the new one. */
14
+ added: {
15
+ index: number;
16
+ item: T;
17
+ }[];
18
+ /** Items that were in the previous result and whose contents changed. */
19
+ changed: T[];
20
+ /** Ids of items that are no longer in the result. */
21
+ removed: any[];
22
+ /** Items that stayed, at their new position, because the order around them changed. */
23
+ moved: {
24
+ index: number;
25
+ id: any;
26
+ }[];
27
+ /** Length of the resulting array — lets a recipient verify it applied the delta to the result it was computed against. */
28
+ resultCount: number;
29
+ }
30
+ /**
31
+ * Checks whether a delta leaves the result it is applied to unchanged.
32
+ * @param delta - The delta to inspect.
33
+ * @returns `true` when applying the delta would be a no-op.
34
+ */
35
+ export declare function isEmptyQueryDelta(delta: QueryDelta<any>): boolean;
36
+ /**
37
+ * Calls a state-change callback, passing the delta only when there is one.
38
+ *
39
+ * A callback invoked as `callback(state, undefined)` has been handed two arguments, which is a
40
+ * different thing from being handed one — visible to anything that inspects arity, and to any test
41
+ * that asserts on the call.
42
+ * @template T - The type of the items.
43
+ * @param callback - The callback to invoke.
44
+ * @param state - The state to report.
45
+ * @param delta - The delta to report, if there is one.
46
+ */
47
+ export declare function callWithDelta<T extends BaseItem>(callback: (state: 'active' | 'complete' | 'error', delta?: QueryDelta<T>) => void, state: 'active' | 'complete' | 'error', delta?: QueryDelta<T>): void;
48
+ /**
49
+ * Checks whether a delta describes a change to the given result.
50
+ *
51
+ * A delta is only meaningful against the exact result it was computed from — it names positions in
52
+ * an array and items by id alone. Applying one to anything else produces a result that looks
53
+ * plausible and is wrong, and from then on every further delta compounds the error. This is the
54
+ * cheap structural check that catches that: every id the delta expects to find is there, every id
55
+ * it expects to be new is not, and the arithmetic on the length works out. It costs the size of the
56
+ * delta, not the size of the result.
57
+ * @template T - The type of the items.
58
+ * @param previous - The result the delta would be applied to.
59
+ * @param delta - The delta to check.
60
+ * @returns `true` when the delta can be applied.
61
+ */
62
+ export declare function canApplyQueryDelta<T extends BaseItem>(previous: T[], delta: QueryDelta<T>): boolean;
63
+ /**
64
+ * Computes the delta between two results of the same query.
65
+ *
66
+ * A fallback for the cases where the change that produced the new result is not available — a query
67
+ * that had to be re-executed in full, for instance. It costs a pass over both results, but it is
68
+ * paid once, on the side that has both of them, instead of shipping the entire new result to
69
+ * everyone who only needs to know what changed.
70
+ * @template T - The type of the items.
71
+ * @param previous - The result the delta should be relative to.
72
+ * @param next - The result the delta should produce.
73
+ * @returns The delta between the two results.
74
+ */
75
+ export declare function diffQueryResults<T extends BaseItem>(previous: T[], next: T[]): QueryDelta<T>;
76
+ /**
77
+ * Applies a delta to the result it was computed against.
78
+ * @template T - The type of the items.
79
+ * @param previous - The result the delta is relative to. Not modified.
80
+ * @param delta - The delta to apply.
81
+ * @returns The resulting items.
82
+ */
83
+ export declare function applyQueryDelta<T extends BaseItem>(previous: T[], delta: QueryDelta<T>): T[];
@@ -1,5 +1,5 @@
1
- import type { QueryOptions } from '../DataAdapter';
2
- import type Selector from '../types/Selector';
1
+ import { QueryOptions } from '../DataAdapter';
2
+ import { default as Selector } from '../types/Selector';
3
3
  /**
4
4
  * Generates a unique identifier for a query based on its selector and options.
5
5
  * @param selector - The selector object.
@@ -0,0 +1,59 @@
1
+ export type MaybePromise<T> = T | Promise<T>;
2
+ /**
3
+ * Options that control execution mode (and potential future mode-specific behavior).
4
+ * Keep this minimal; you can extend it later (e.g. signal, timeoutMs, debugLabel).
5
+ */
6
+ export type ModeOptions = {
7
+ async?: boolean;
8
+ };
9
+ /**
10
+ * A generator helper that makes TypeScript infer the “synchronous value type” for maybe-async expressions.
11
+ *
12
+ * Usage:
13
+ * const doc = yield* unwrap(Collection.findOne(...))
14
+ * const list = yield* unwrap(Collection.find(...).fetch())
15
+ *
16
+ * Runtime note:
17
+ * This does not “unwrap” Promises by itself. It yields the value/Promise to the runner and returns the
18
+ * value that the runner feeds back via `.next(...)`.
19
+ * @param value The value (or Promise of a value) to yield to the runner.
20
+ * @returns A generator that yields `value` and resolves to the runner-supplied unwrapped `T`.
21
+ */
22
+ export declare function unwrap<T>(value: MaybePromise<T>): Generator<MaybePromise<T>, T, T>;
23
+ /**
24
+ * Generator shape used by the factory.
25
+ *
26
+ * `TThis` is the type of `this` inside the generator.
27
+ * `Args` are the method parameters (excluding the mode flag).
28
+ * `TReturn` is the final return value of the workflow.
29
+ * `TNext` is the type that is yielded/awaited and fed back via `.next(...)`.
30
+ *
31
+ * Note:
32
+ * - For best inference at yield sites, prefer `yield* unwrap(expr)` for maybe-async expressions.
33
+ */
34
+ export type ReactiveOrAsyncGen<TThis, Arguments extends any[], TReturn, TNext> = (this: TThis, a: boolean, ...args: Arguments) => Generator<MaybePromise<TNext>, TReturn, TNext>;
35
+ /**
36
+ * The method type produced from the generator signature.
37
+ * Adds overloads so that `{ async: true }` yields a `Promise<...>` return type.
38
+ */
39
+ export type ReactiveOrAsyncMethod<TThis, P extends any[], R, N> = {
40
+ (this: TThis, ...args: P): R;
41
+ (this: TThis, ...args: [...P, ModeOptions?]): MaybePromise<R>;
42
+ (this: TThis, ...args: [...P, {
43
+ async: true;
44
+ }]): Promise<R>;
45
+ } & {
46
+ /** Exposes the underlying generator for composition via `yield* method.generator.call(this, a, ...)` */
47
+ generator: (this: TThis, a: boolean, ...args: P) => Generator<MaybePromise<N>, R, N>;
48
+ };
49
+ /**
50
+ * Factory that turns a generator workflow into a callable method that can run in sync (reactive) or async mode.
51
+ *
52
+ * Call style:
53
+ * fn(a, b) -> sync/reactive return
54
+ * await fn(a, b, { async: true }) -> async return
55
+ * @param gen Generator workflow. Receives `(a)` which indicates async mode and should `yield`/`yield* unwrap(...)`
56
+ * any values that may be Promises.
57
+ * @returns A callable method with overloads plus a `.generator` property for composition.
58
+ */
59
+ export default function reactiveOrAsync<TThis, P extends any[], R, N>(gen: (this: TThis, a: boolean, ...args: P) => Generator<MaybePromise<N>, R, N>): ReactiveOrAsyncMethod<TThis, P, R, N>;
@@ -0,0 +1,20 @@
1
+ import { BaseItem } from '../Collection/types';
2
+ import { default as StorageAdapter } from '../types/StorageAdapter';
3
+ import { AsynchronousQueryFunction } from '../types/IndexProvider';
4
+ /**
5
+ * Builds the index provider a data adapter uses to narrow a selector down through
6
+ * a storage adapter's index.
7
+ *
8
+ * Every adapter that keeps its data in a `StorageAdapter` needs exactly this, and
9
+ * each of them used to carry its own copy — three transcriptions of one set of
10
+ * rules about null, `$exists`, inclusion and exclusion, which is how they drift
11
+ * apart without anyone noticing. The index is keyed by `serializeValue(value)`,
12
+ * which is what `getMatchingKeys` produces, so the two only agree while they stay
13
+ * in one place.
14
+ * @template T - The type of the items in the collection.
15
+ * @template I - The type of the unique identifier for the items.
16
+ * @param storage - The storage adapter holding the index.
17
+ * @param field - The indexed field this provider answers for.
18
+ * @returns A query function for `getIndexInfo`.
19
+ */
20
+ export default function storageIndexQuery<T extends BaseItem<I>, I = any>(storage: Pick<StorageAdapter<T, I>, 'readIndex'>, field: string): AsynchronousQueryFunction<T, I>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signaldb/core",
3
- "version": "2.0.0-beta.2",
3
+ "version": "2.0.0-beta.21",
4
4
  "description": "SignalDB is a client-side database that provides a simple MongoDB-like interface to the data with first-class typescript support to achieve an optimistic UI. Data persistence can be achieved by using storage providers that store the data through a JSON interface to places such as localStorage.",
5
5
  "scripts": {
6
6
  "build": "rimraf dist && vite build",
@@ -1,18 +0,0 @@
1
- "use strict";
2
- function get(value, path) {
3
- const normalized = path.replaceAll(/\[(\w+)\]/g, ".$1");
4
- if (normalized.includes("..") || normalized.startsWith(".") || normalized.endsWith(".")) {
5
- return;
6
- }
7
- const segments = normalized.split(".");
8
- let current = value;
9
- for (const key of segments) {
10
- if (current == null)
11
- return;
12
- current = current[key];
13
- }
14
- if (current === void 0)
15
- return;
16
- return current;
17
- }
18
- module.exports = get;
@@ -1,15 +0,0 @@
1
- "use strict";
2
- function serializeValue(value) {
3
- if (value == null)
4
- return null;
5
- if (typeof value === "string")
6
- return value;
7
- if (typeof value === "number")
8
- return value.toString();
9
- if (typeof value === "boolean")
10
- return value.toString();
11
- if (value instanceof Date)
12
- return value.toISOString();
13
- return JSON.stringify(value);
14
- }
15
- module.exports = serializeValue;