@powersync/common 1.32.0 → 1.33.1
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/dist/bundle.cjs +22 -0
- package/dist/bundle.mjs +5 -5
- package/lib/client/ConnectionManager.js +0 -1
- package/lib/client/sync/bucket/BucketStorageAdapter.d.ts +15 -9
- package/lib/client/sync/bucket/BucketStorageAdapter.js +9 -0
- package/lib/client/sync/bucket/CrudEntry.d.ts +2 -0
- package/lib/client/sync/bucket/CrudEntry.js +13 -2
- package/lib/client/sync/bucket/OplogEntry.d.ts +4 -4
- package/lib/client/sync/bucket/OplogEntry.js +5 -3
- package/lib/client/sync/bucket/SqliteBucketStorage.d.ts +6 -14
- package/lib/client/sync/bucket/SqliteBucketStorage.js +24 -44
- package/lib/client/sync/bucket/SyncDataBucket.d.ts +1 -1
- package/lib/client/sync/bucket/SyncDataBucket.js +2 -2
- package/lib/client/sync/stream/AbstractRemote.d.ts +15 -3
- package/lib/client/sync/stream/AbstractRemote.js +95 -83
- package/lib/client/sync/stream/AbstractStreamingSyncImplementation.d.ts +69 -0
- package/lib/client/sync/stream/AbstractStreamingSyncImplementation.js +462 -217
- package/lib/client/sync/stream/core-instruction.d.ts +53 -0
- package/lib/client/sync/stream/core-instruction.js +1 -0
- package/lib/db/crud/SyncProgress.d.ts +2 -6
- package/lib/db/crud/SyncProgress.js +2 -2
- package/lib/utils/DataStream.d.ts +13 -14
- package/lib/utils/DataStream.js +27 -29
- package/package.json +4 -4
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { StreamingSyncRequest } from './streaming-sync-types.js';
|
|
2
|
+
/**
|
|
3
|
+
* An internal instruction emitted by the sync client in the core extension in response to the JS
|
|
4
|
+
* SDK passing sync data into the extension.
|
|
5
|
+
*/
|
|
6
|
+
export type Instruction = {
|
|
7
|
+
LogLine: LogLine;
|
|
8
|
+
} | {
|
|
9
|
+
UpdateSyncStatus: UpdateSyncStatus;
|
|
10
|
+
} | {
|
|
11
|
+
EstablishSyncStream: EstablishSyncStream;
|
|
12
|
+
} | {
|
|
13
|
+
FetchCredentials: FetchCredentials;
|
|
14
|
+
} | {
|
|
15
|
+
CloseSyncStream: any;
|
|
16
|
+
} | {
|
|
17
|
+
FlushFileSystem: any;
|
|
18
|
+
} | {
|
|
19
|
+
DidCompleteSync: any;
|
|
20
|
+
};
|
|
21
|
+
export interface LogLine {
|
|
22
|
+
severity: 'DEBUG' | 'INFO' | 'WARNING';
|
|
23
|
+
line: string;
|
|
24
|
+
}
|
|
25
|
+
export interface EstablishSyncStream {
|
|
26
|
+
request: StreamingSyncRequest;
|
|
27
|
+
}
|
|
28
|
+
export interface UpdateSyncStatus {
|
|
29
|
+
status: CoreSyncStatus;
|
|
30
|
+
}
|
|
31
|
+
export interface CoreSyncStatus {
|
|
32
|
+
connected: boolean;
|
|
33
|
+
connecting: boolean;
|
|
34
|
+
priority_status: SyncPriorityStatus[];
|
|
35
|
+
downloading: DownloadProgress | null;
|
|
36
|
+
}
|
|
37
|
+
export interface SyncPriorityStatus {
|
|
38
|
+
priority: number;
|
|
39
|
+
last_synced_at: number | number;
|
|
40
|
+
has_synced: boolean | null;
|
|
41
|
+
}
|
|
42
|
+
export interface DownloadProgress {
|
|
43
|
+
buckets: Record<string, BucketProgress>;
|
|
44
|
+
}
|
|
45
|
+
export interface BucketProgress {
|
|
46
|
+
priority: number;
|
|
47
|
+
at_last: number;
|
|
48
|
+
since_last: number;
|
|
49
|
+
target_count: number;
|
|
50
|
+
}
|
|
51
|
+
export interface FetchCredentials {
|
|
52
|
+
did_expire: boolean;
|
|
53
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,10 +1,6 @@
|
|
|
1
|
+
import { BucketProgress } from 'src/client/sync/stream/core-instruction.js';
|
|
1
2
|
/** @internal */
|
|
2
|
-
export type InternalProgressInformation = Record<string,
|
|
3
|
-
priority: number;
|
|
4
|
-
atLast: number;
|
|
5
|
-
sinceLast: number;
|
|
6
|
-
targetCount: number;
|
|
7
|
-
}>;
|
|
3
|
+
export type InternalProgressInformation = Record<string, BucketProgress>;
|
|
8
4
|
/**
|
|
9
5
|
* @internal The priority used by the core extension to indicate that a full sync was completed.
|
|
10
6
|
*/
|
|
@@ -46,8 +46,8 @@ export class SyncProgress {
|
|
|
46
46
|
for (const progress of Object.values(this.internal)) {
|
|
47
47
|
// Include higher-priority buckets, which are represented by lower numbers.
|
|
48
48
|
if (progress.priority <= priority) {
|
|
49
|
-
downloaded += progress.
|
|
50
|
-
total += progress.
|
|
49
|
+
downloaded += progress.since_last;
|
|
50
|
+
total += progress.target_count - progress.at_last;
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
let progress = total == 0 ? 0.0 : downloaded / total;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ILogger } from 'js-logger';
|
|
2
2
|
import { BaseListener, BaseObserver } from './BaseObserver.js';
|
|
3
|
-
export type DataStreamOptions = {
|
|
3
|
+
export type DataStreamOptions<ParsedData, SourceData> = {
|
|
4
|
+
mapLine?: (line: SourceData) => ParsedData;
|
|
4
5
|
/**
|
|
5
6
|
* Close the stream if any consumer throws an error
|
|
6
7
|
*/
|
|
@@ -28,13 +29,15 @@ export declare const DEFAULT_PRESSURE_LIMITS: {
|
|
|
28
29
|
* native JS streams or async iterators.
|
|
29
30
|
* This is handy for environments such as React Native which need polyfills for the above.
|
|
30
31
|
*/
|
|
31
|
-
export declare class DataStream<
|
|
32
|
-
protected options?: DataStreamOptions | undefined;
|
|
33
|
-
dataQueue:
|
|
32
|
+
export declare class DataStream<ParsedData, SourceData = any> extends BaseObserver<DataStreamListener<ParsedData>> {
|
|
33
|
+
protected options?: DataStreamOptions<ParsedData, SourceData> | undefined;
|
|
34
|
+
dataQueue: SourceData[];
|
|
34
35
|
protected isClosed: boolean;
|
|
35
36
|
protected processingPromise: Promise<void> | null;
|
|
37
|
+
protected notifyDataAdded: (() => void) | null;
|
|
36
38
|
protected logger: ILogger;
|
|
37
|
-
|
|
39
|
+
protected mapLine: (line: SourceData) => ParsedData;
|
|
40
|
+
constructor(options?: DataStreamOptions<ParsedData, SourceData> | undefined);
|
|
38
41
|
get highWatermark(): number;
|
|
39
42
|
get lowWatermark(): number;
|
|
40
43
|
get closed(): boolean;
|
|
@@ -42,22 +45,18 @@ export declare class DataStream<Data extends any = any> extends BaseObserver<Dat
|
|
|
42
45
|
/**
|
|
43
46
|
* Enqueues data for the consumers to read
|
|
44
47
|
*/
|
|
45
|
-
enqueueData(data:
|
|
48
|
+
enqueueData(data: SourceData): void;
|
|
46
49
|
/**
|
|
47
50
|
* Reads data once from the data stream
|
|
48
51
|
* @returns a Data payload or Null if the stream closed.
|
|
49
52
|
*/
|
|
50
|
-
read(): Promise<
|
|
53
|
+
read(): Promise<ParsedData | null>;
|
|
51
54
|
/**
|
|
52
55
|
* Executes a callback for each data item in the stream
|
|
53
56
|
*/
|
|
54
|
-
forEach(callback: DataStreamCallback<
|
|
55
|
-
protected processQueue(): Promise<void
|
|
56
|
-
/**
|
|
57
|
-
* Creates a new data stream which is a map of the original
|
|
58
|
-
*/
|
|
59
|
-
map<ReturnData>(callback: (data: Data) => ReturnData): DataStream<ReturnData>;
|
|
57
|
+
forEach(callback: DataStreamCallback<ParsedData>): () => void;
|
|
58
|
+
protected processQueue(): Promise<void> | undefined;
|
|
60
59
|
protected hasDataReader(): boolean;
|
|
61
60
|
protected _processQueue(): Promise<void>;
|
|
62
|
-
protected iterateAsyncErrored(cb: (l:
|
|
61
|
+
protected iterateAsyncErrored(cb: (l: Partial<DataStreamListener<ParsedData>>) => Promise<void>): Promise<void>;
|
|
63
62
|
}
|
package/lib/utils/DataStream.js
CHANGED
|
@@ -14,13 +14,16 @@ export class DataStream extends BaseObserver {
|
|
|
14
14
|
dataQueue;
|
|
15
15
|
isClosed;
|
|
16
16
|
processingPromise;
|
|
17
|
+
notifyDataAdded;
|
|
17
18
|
logger;
|
|
19
|
+
mapLine;
|
|
18
20
|
constructor(options) {
|
|
19
21
|
super();
|
|
20
22
|
this.options = options;
|
|
21
23
|
this.processingPromise = null;
|
|
22
24
|
this.isClosed = false;
|
|
23
25
|
this.dataQueue = [];
|
|
26
|
+
this.mapLine = options?.mapLine ?? ((line) => line);
|
|
24
27
|
this.logger = options?.logger ?? Logger.get('DataStream');
|
|
25
28
|
if (options?.closeOnError) {
|
|
26
29
|
const l = this.registerListener({
|
|
@@ -56,6 +59,7 @@ export class DataStream extends BaseObserver {
|
|
|
56
59
|
throw new Error('Cannot enqueue data into closed stream.');
|
|
57
60
|
}
|
|
58
61
|
this.dataQueue.push(data);
|
|
62
|
+
this.notifyDataAdded?.();
|
|
59
63
|
this.processQueue();
|
|
60
64
|
}
|
|
61
65
|
/**
|
|
@@ -96,10 +100,20 @@ export class DataStream extends BaseObserver {
|
|
|
96
100
|
data: callback
|
|
97
101
|
});
|
|
98
102
|
}
|
|
99
|
-
|
|
103
|
+
processQueue() {
|
|
100
104
|
if (this.processingPromise) {
|
|
101
105
|
return;
|
|
102
106
|
}
|
|
107
|
+
const promise = (this.processingPromise = this._processQueue());
|
|
108
|
+
promise.finally(() => {
|
|
109
|
+
return (this.processingPromise = null);
|
|
110
|
+
});
|
|
111
|
+
return promise;
|
|
112
|
+
}
|
|
113
|
+
hasDataReader() {
|
|
114
|
+
return Array.from(this.listeners.values()).some((l) => !!l.data);
|
|
115
|
+
}
|
|
116
|
+
async _processQueue() {
|
|
103
117
|
/**
|
|
104
118
|
* Allow listeners to mutate the queue before processing.
|
|
105
119
|
* This allows for operations such as dropping or compressing data
|
|
@@ -108,47 +122,31 @@ export class DataStream extends BaseObserver {
|
|
|
108
122
|
if (this.dataQueue.length >= this.highWatermark) {
|
|
109
123
|
await this.iterateAsyncErrored(async (l) => l.highWater?.());
|
|
110
124
|
}
|
|
111
|
-
return (this.processingPromise = this._processQueue());
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Creates a new data stream which is a map of the original
|
|
115
|
-
*/
|
|
116
|
-
map(callback) {
|
|
117
|
-
const stream = new DataStream(this.options);
|
|
118
|
-
const l = this.registerListener({
|
|
119
|
-
data: async (data) => {
|
|
120
|
-
stream.enqueueData(callback(data));
|
|
121
|
-
},
|
|
122
|
-
closed: () => {
|
|
123
|
-
stream.close();
|
|
124
|
-
l?.();
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
return stream;
|
|
128
|
-
}
|
|
129
|
-
hasDataReader() {
|
|
130
|
-
return Array.from(this.listeners.values()).some((l) => !!l.data);
|
|
131
|
-
}
|
|
132
|
-
async _processQueue() {
|
|
133
125
|
if (this.isClosed || !this.hasDataReader()) {
|
|
134
|
-
Promise.resolve().then(() => (this.processingPromise = null));
|
|
135
126
|
return;
|
|
136
127
|
}
|
|
137
128
|
if (this.dataQueue.length) {
|
|
138
129
|
const data = this.dataQueue.shift();
|
|
139
|
-
|
|
130
|
+
const mapped = this.mapLine(data);
|
|
131
|
+
await this.iterateAsyncErrored(async (l) => l.data?.(mapped));
|
|
140
132
|
}
|
|
141
133
|
if (this.dataQueue.length <= this.lowWatermark) {
|
|
142
|
-
|
|
134
|
+
const dataAdded = new Promise((resolve) => {
|
|
135
|
+
this.notifyDataAdded = resolve;
|
|
136
|
+
});
|
|
137
|
+
await Promise.race([this.iterateAsyncErrored(async (l) => l.lowWater?.()), dataAdded]);
|
|
138
|
+
this.notifyDataAdded = null;
|
|
143
139
|
}
|
|
144
|
-
this.
|
|
145
|
-
if (this.dataQueue.length) {
|
|
140
|
+
if (this.dataQueue.length > 0) {
|
|
146
141
|
// Next tick
|
|
147
142
|
setTimeout(() => this.processQueue());
|
|
148
143
|
}
|
|
149
144
|
}
|
|
150
145
|
async iterateAsyncErrored(cb) {
|
|
151
|
-
|
|
146
|
+
// Important: We need to copy the listeners, as calling a listener could result in adding another
|
|
147
|
+
// listener, resulting in infinite loops.
|
|
148
|
+
const listeners = Array.from(this.listeners.values());
|
|
149
|
+
for (let i of listeners) {
|
|
152
150
|
try {
|
|
153
151
|
await cb(i);
|
|
154
152
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@powersync/common",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.33.1",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"registry": "https://registry.npmjs.org/",
|
|
6
6
|
"access": "public"
|
|
@@ -13,8 +13,9 @@
|
|
|
13
13
|
"exports": {
|
|
14
14
|
".": {
|
|
15
15
|
"import": "./dist/bundle.mjs",
|
|
16
|
-
"
|
|
17
|
-
"types": "./lib/index.d.ts"
|
|
16
|
+
"require": "./dist/bundle.cjs",
|
|
17
|
+
"types": "./lib/index.d.ts",
|
|
18
|
+
"default": "./dist/bundle.mjs"
|
|
18
19
|
}
|
|
19
20
|
},
|
|
20
21
|
"author": "JOURNEYAPPS",
|
|
@@ -45,7 +46,6 @@
|
|
|
45
46
|
"async-mutex": "^0.4.0",
|
|
46
47
|
"bson": "^6.6.0",
|
|
47
48
|
"buffer": "^6.0.3",
|
|
48
|
-
"can-ndjson-stream": "^1.0.2",
|
|
49
49
|
"cross-fetch": "^4.0.0",
|
|
50
50
|
"event-iterator": "^2.0.0",
|
|
51
51
|
"rollup": "4.14.3",
|