@powersync/common 1.51.0 → 1.52.0

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 (37) hide show
  1. package/dist/bundle.cjs +431 -445
  2. package/dist/bundle.cjs.map +1 -1
  3. package/dist/bundle.mjs +432 -444
  4. package/dist/bundle.mjs.map +1 -1
  5. package/dist/bundle.node.cjs +429 -445
  6. package/dist/bundle.node.cjs.map +1 -1
  7. package/dist/bundle.node.mjs +430 -444
  8. package/dist/bundle.node.mjs.map +1 -1
  9. package/dist/index.d.cts +41 -70
  10. package/lib/client/AbstractPowerSyncDatabase.js +3 -3
  11. package/lib/client/AbstractPowerSyncDatabase.js.map +1 -1
  12. package/lib/client/sync/stream/AbstractRemote.d.ts +29 -8
  13. package/lib/client/sync/stream/AbstractRemote.js +154 -177
  14. package/lib/client/sync/stream/AbstractRemote.js.map +1 -1
  15. package/lib/client/sync/stream/AbstractStreamingSyncImplementation.d.ts +1 -0
  16. package/lib/client/sync/stream/AbstractStreamingSyncImplementation.js +69 -88
  17. package/lib/client/sync/stream/AbstractStreamingSyncImplementation.js.map +1 -1
  18. package/lib/index.d.ts +1 -1
  19. package/lib/index.js +0 -1
  20. package/lib/index.js.map +1 -1
  21. package/lib/utils/async.d.ts +0 -9
  22. package/lib/utils/async.js +0 -9
  23. package/lib/utils/async.js.map +1 -1
  24. package/lib/utils/stream_transform.d.ts +39 -0
  25. package/lib/utils/stream_transform.js +206 -0
  26. package/lib/utils/stream_transform.js.map +1 -0
  27. package/package.json +9 -7
  28. package/src/client/AbstractPowerSyncDatabase.ts +3 -3
  29. package/src/client/sync/stream/AbstractRemote.ts +182 -206
  30. package/src/client/sync/stream/AbstractStreamingSyncImplementation.ts +82 -83
  31. package/src/index.ts +1 -1
  32. package/src/utils/async.ts +0 -11
  33. package/src/utils/stream_transform.ts +252 -0
  34. package/lib/utils/DataStream.d.ts +0 -62
  35. package/lib/utils/DataStream.js +0 -169
  36. package/lib/utils/DataStream.js.map +0 -1
  37. package/src/utils/DataStream.ts +0 -222
@@ -1,169 +0,0 @@
1
- import Logger from 'js-logger';
2
- import { BaseObserver } from './BaseObserver.js';
3
- export const DEFAULT_PRESSURE_LIMITS = {
4
- highWater: 10,
5
- lowWater: 0
6
- };
7
- /**
8
- * A very basic implementation of a data stream with backpressure support which does not use
9
- * native JS streams or async iterators.
10
- * This is handy for environments such as React Native which need polyfills for the above.
11
- */
12
- export class DataStream extends BaseObserver {
13
- options;
14
- dataQueue;
15
- isClosed;
16
- processingPromise;
17
- notifyDataAdded;
18
- logger;
19
- mapLine;
20
- constructor(options) {
21
- super();
22
- this.options = options;
23
- this.processingPromise = null;
24
- this.isClosed = false;
25
- this.dataQueue = [];
26
- this.mapLine = options?.mapLine ?? ((line) => line);
27
- this.logger = options?.logger ?? Logger.get('DataStream');
28
- if (options?.closeOnError) {
29
- const l = this.registerListener({
30
- error: (ex) => {
31
- l?.();
32
- this.close();
33
- }
34
- });
35
- }
36
- }
37
- get highWatermark() {
38
- return this.options?.pressure?.highWaterMark ?? DEFAULT_PRESSURE_LIMITS.highWater;
39
- }
40
- get lowWatermark() {
41
- return this.options?.pressure?.lowWaterMark ?? DEFAULT_PRESSURE_LIMITS.lowWater;
42
- }
43
- get closed() {
44
- return this.isClosed;
45
- }
46
- async close() {
47
- this.isClosed = true;
48
- await this.processingPromise;
49
- this.iterateListeners((l) => l.closed?.());
50
- // Discard any data in the queue
51
- this.dataQueue = [];
52
- this.listeners.clear();
53
- }
54
- /**
55
- * Enqueues data for the consumers to read
56
- */
57
- enqueueData(data) {
58
- if (this.isClosed) {
59
- throw new Error('Cannot enqueue data into closed stream.');
60
- }
61
- this.dataQueue.push(data);
62
- this.notifyDataAdded?.();
63
- this.processQueue();
64
- }
65
- /**
66
- * Reads data once from the data stream
67
- * @returns a Data payload or Null if the stream closed.
68
- */
69
- async read() {
70
- if (this.closed) {
71
- return null;
72
- }
73
- // Wait for any pending processing to complete first.
74
- // This ensures we register our listener before calling processQueue(),
75
- // avoiding a race where processQueue() sees no reader and returns early.
76
- if (this.processingPromise) {
77
- await this.processingPromise;
78
- }
79
- // Re-check after await - stream may have closed while we were waiting
80
- if (this.closed) {
81
- return null;
82
- }
83
- return new Promise((resolve, reject) => {
84
- const l = this.registerListener({
85
- data: async (data) => {
86
- resolve(data);
87
- // Remove the listener
88
- l?.();
89
- },
90
- closed: () => {
91
- resolve(null);
92
- l?.();
93
- },
94
- error: (ex) => {
95
- reject(ex);
96
- l?.();
97
- }
98
- });
99
- this.processQueue();
100
- });
101
- }
102
- /**
103
- * Executes a callback for each data item in the stream
104
- */
105
- forEach(callback) {
106
- if (this.dataQueue.length <= this.lowWatermark) {
107
- this.iterateAsyncErrored(async (l) => l.lowWater?.());
108
- }
109
- return this.registerListener({
110
- data: callback
111
- });
112
- }
113
- processQueue() {
114
- if (this.processingPromise) {
115
- return;
116
- }
117
- const promise = (this.processingPromise = this._processQueue());
118
- promise.finally(() => {
119
- this.processingPromise = null;
120
- });
121
- return promise;
122
- }
123
- hasDataReader() {
124
- return Array.from(this.listeners.values()).some((l) => !!l.data);
125
- }
126
- async _processQueue() {
127
- /**
128
- * Allow listeners to mutate the queue before processing.
129
- * This allows for operations such as dropping or compressing data
130
- * on high water or requesting more data on low water.
131
- */
132
- if (this.dataQueue.length >= this.highWatermark) {
133
- await this.iterateAsyncErrored(async (l) => l.highWater?.());
134
- }
135
- if (this.isClosed || !this.hasDataReader()) {
136
- return;
137
- }
138
- if (this.dataQueue.length) {
139
- const data = this.dataQueue.shift();
140
- const mapped = this.mapLine(data);
141
- await this.iterateAsyncErrored(async (l) => l.data?.(mapped));
142
- }
143
- if (this.dataQueue.length <= this.lowWatermark) {
144
- const dataAdded = new Promise((resolve) => {
145
- this.notifyDataAdded = resolve;
146
- });
147
- await Promise.race([this.iterateAsyncErrored(async (l) => l.lowWater?.()), dataAdded]);
148
- this.notifyDataAdded = null;
149
- }
150
- if (this.dataQueue.length > 0) {
151
- setTimeout(() => this.processQueue());
152
- }
153
- }
154
- async iterateAsyncErrored(cb) {
155
- // Important: We need to copy the listeners, as calling a listener could result in adding another
156
- // listener, resulting in infinite loops.
157
- const listeners = Array.from(this.listeners.values());
158
- for (let i of listeners) {
159
- try {
160
- await cb(i);
161
- }
162
- catch (ex) {
163
- this.logger.error(ex);
164
- this.iterateListeners((l) => l.error?.(ex));
165
- }
166
- }
167
- }
168
- }
169
- //# sourceMappingURL=DataStream.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DataStream.js","sourceRoot":"","sources":["../../src/utils/DataStream.ts"],"names":[],"mappings":"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"}
@@ -1,222 +0,0 @@
1
- import Logger, { ILogger } from 'js-logger';
2
- import { BaseListener, BaseObserver } from './BaseObserver.js';
3
-
4
- export type DataStreamOptions<ParsedData, SourceData> = {
5
- mapLine?: (line: SourceData) => ParsedData;
6
-
7
- /**
8
- * Close the stream if any consumer throws an error
9
- */
10
- closeOnError?: boolean;
11
- pressure?: {
12
- highWaterMark?: number;
13
- lowWaterMark?: number;
14
- };
15
- logger?: ILogger;
16
- };
17
-
18
- export type DataStreamCallback<Data extends any = any> = (data: Data) => Promise<void>;
19
-
20
- export interface DataStreamListener<Data extends any = any> extends BaseListener {
21
- data: (data: Data) => Promise<void>;
22
- closed: () => void;
23
- error: (error: Error) => void;
24
- highWater: () => Promise<void>;
25
- lowWater: () => Promise<void>;
26
- }
27
-
28
- export const DEFAULT_PRESSURE_LIMITS = {
29
- highWater: 10,
30
- lowWater: 0
31
- };
32
-
33
- /**
34
- * A very basic implementation of a data stream with backpressure support which does not use
35
- * native JS streams or async iterators.
36
- * This is handy for environments such as React Native which need polyfills for the above.
37
- */
38
- export class DataStream<ParsedData, SourceData = any> extends BaseObserver<DataStreamListener<ParsedData>> {
39
- dataQueue: SourceData[];
40
-
41
- protected isClosed: boolean;
42
-
43
- protected processingPromise: Promise<void> | null;
44
- protected notifyDataAdded: (() => void) | null;
45
-
46
- protected logger: ILogger;
47
-
48
- protected mapLine: (line: SourceData) => ParsedData;
49
-
50
- constructor(protected options?: DataStreamOptions<ParsedData, SourceData>) {
51
- super();
52
- this.processingPromise = null;
53
- this.isClosed = false;
54
- this.dataQueue = [];
55
- this.mapLine = options?.mapLine ?? ((line) => line as any);
56
-
57
- this.logger = options?.logger ?? Logger.get('DataStream');
58
-
59
- if (options?.closeOnError) {
60
- const l = this.registerListener({
61
- error: (ex) => {
62
- l?.();
63
- this.close();
64
- }
65
- });
66
- }
67
- }
68
-
69
- get highWatermark() {
70
- return this.options?.pressure?.highWaterMark ?? DEFAULT_PRESSURE_LIMITS.highWater;
71
- }
72
-
73
- get lowWatermark() {
74
- return this.options?.pressure?.lowWaterMark ?? DEFAULT_PRESSURE_LIMITS.lowWater;
75
- }
76
-
77
- get closed() {
78
- return this.isClosed;
79
- }
80
-
81
- async close() {
82
- this.isClosed = true;
83
- await this.processingPromise;
84
- this.iterateListeners((l) => l.closed?.());
85
- // Discard any data in the queue
86
- this.dataQueue = [];
87
- this.listeners.clear();
88
- }
89
-
90
- /**
91
- * Enqueues data for the consumers to read
92
- */
93
- enqueueData(data: SourceData) {
94
- if (this.isClosed) {
95
- throw new Error('Cannot enqueue data into closed stream.');
96
- }
97
-
98
- this.dataQueue.push(data);
99
- this.notifyDataAdded?.();
100
-
101
- this.processQueue();
102
- }
103
-
104
- /**
105
- * Reads data once from the data stream
106
- * @returns a Data payload or Null if the stream closed.
107
- */
108
- async read(): Promise<ParsedData | null> {
109
- if (this.closed) {
110
- return null;
111
- }
112
-
113
- // Wait for any pending processing to complete first.
114
- // This ensures we register our listener before calling processQueue(),
115
- // avoiding a race where processQueue() sees no reader and returns early.
116
- if (this.processingPromise) {
117
- await this.processingPromise;
118
- }
119
-
120
- // Re-check after await - stream may have closed while we were waiting
121
- if (this.closed) {
122
- return null;
123
- }
124
-
125
- return new Promise((resolve, reject) => {
126
- const l = this.registerListener({
127
- data: async (data) => {
128
- resolve(data);
129
- // Remove the listener
130
- l?.();
131
- },
132
- closed: () => {
133
- resolve(null);
134
- l?.();
135
- },
136
- error: (ex) => {
137
- reject(ex);
138
- l?.();
139
- }
140
- });
141
-
142
- this.processQueue();
143
- });
144
- }
145
-
146
- /**
147
- * Executes a callback for each data item in the stream
148
- */
149
- forEach(callback: DataStreamCallback<ParsedData>) {
150
- if (this.dataQueue.length <= this.lowWatermark) {
151
- this.iterateAsyncErrored(async (l) => l.lowWater?.());
152
- }
153
-
154
- return this.registerListener({
155
- data: callback
156
- });
157
- }
158
-
159
- protected processQueue() {
160
- if (this.processingPromise) {
161
- return;
162
- }
163
-
164
- const promise = (this.processingPromise = this._processQueue());
165
- promise.finally(() => {
166
- this.processingPromise = null;
167
- });
168
- return promise;
169
- }
170
-
171
- protected hasDataReader() {
172
- return Array.from(this.listeners.values()).some((l) => !!l.data);
173
- }
174
-
175
- protected async _processQueue() {
176
- /**
177
- * Allow listeners to mutate the queue before processing.
178
- * This allows for operations such as dropping or compressing data
179
- * on high water or requesting more data on low water.
180
- */
181
- if (this.dataQueue.length >= this.highWatermark) {
182
- await this.iterateAsyncErrored(async (l) => l.highWater?.());
183
- }
184
-
185
- if (this.isClosed || !this.hasDataReader()) {
186
- return;
187
- }
188
-
189
- if (this.dataQueue.length) {
190
- const data = this.dataQueue.shift()!;
191
- const mapped = this.mapLine(data);
192
- await this.iterateAsyncErrored(async (l) => l.data?.(mapped));
193
- }
194
-
195
- if (this.dataQueue.length <= this.lowWatermark) {
196
- const dataAdded = new Promise<void>((resolve) => {
197
- this.notifyDataAdded = resolve;
198
- });
199
-
200
- await Promise.race([this.iterateAsyncErrored(async (l) => l.lowWater?.()), dataAdded]);
201
- this.notifyDataAdded = null;
202
- }
203
-
204
- if (this.dataQueue.length > 0) {
205
- setTimeout(() => this.processQueue());
206
- }
207
- }
208
-
209
- protected async iterateAsyncErrored(cb: (l: Partial<DataStreamListener<ParsedData>>) => Promise<void>) {
210
- // Important: We need to copy the listeners, as calling a listener could result in adding another
211
- // listener, resulting in infinite loops.
212
- const listeners = Array.from(this.listeners.values());
213
- for (let i of listeners) {
214
- try {
215
- await cb(i);
216
- } catch (ex) {
217
- this.logger.error(ex);
218
- this.iterateListeners((l) => l.error?.(ex));
219
- }
220
- }
221
- }
222
- }