@powersync/common 0.0.0-dev-20250714151300 → 0.0.0-dev-20250715080712
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 +1 -1
- package/dist/bundle.mjs +1 -1
- package/lib/client/AbstractPowerSyncDatabase.js +3 -1
- package/lib/client/ConnectionManager.d.ts +4 -4
- package/lib/client/sync/stream/AbstractStreamingSyncImplementation.d.ts +7 -2
- package/lib/client/sync/stream/AbstractStreamingSyncImplementation.js +18 -4
- package/lib/db/schema/RawTable.d.ts +57 -0
- package/lib/db/schema/RawTable.js +28 -0
- package/lib/db/schema/Schema.d.ts +14 -0
- package/lib/db/schema/Schema.js +20 -1
- package/package.json +1 -1
|
@@ -299,7 +299,9 @@ export class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
299
299
|
* Connects to stream of events from the PowerSync instance.
|
|
300
300
|
*/
|
|
301
301
|
async connect(connector, options) {
|
|
302
|
-
|
|
302
|
+
const resolvedOptions = options ?? {};
|
|
303
|
+
resolvedOptions.serializedSchema = this.schema.toJSON();
|
|
304
|
+
return this.connectionManager.connect(connector, resolvedOptions);
|
|
303
305
|
}
|
|
304
306
|
/**
|
|
305
307
|
* Close the sync connection.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ILogger } from 'js-logger';
|
|
2
2
|
import { BaseListener, BaseObserver } from '../utils/BaseObserver.js';
|
|
3
3
|
import { PowerSyncBackendConnector } from './connection/PowerSyncBackendConnector.js';
|
|
4
|
-
import {
|
|
4
|
+
import { InternalConnectionOptions, StreamingSyncImplementation } from './sync/stream/AbstractStreamingSyncImplementation.js';
|
|
5
5
|
/**
|
|
6
6
|
* @internal
|
|
7
7
|
*/
|
|
@@ -17,12 +17,12 @@ export interface ConnectionManagerSyncImplementationResult {
|
|
|
17
17
|
* @internal
|
|
18
18
|
*/
|
|
19
19
|
export interface ConnectionManagerOptions {
|
|
20
|
-
createSyncImplementation(connector: PowerSyncBackendConnector, options:
|
|
20
|
+
createSyncImplementation(connector: PowerSyncBackendConnector, options: InternalConnectionOptions): Promise<ConnectionManagerSyncImplementationResult>;
|
|
21
21
|
logger: ILogger;
|
|
22
22
|
}
|
|
23
23
|
type StoredConnectionOptions = {
|
|
24
24
|
connector: PowerSyncBackendConnector;
|
|
25
|
-
options:
|
|
25
|
+
options: InternalConnectionOptions;
|
|
26
26
|
};
|
|
27
27
|
/**
|
|
28
28
|
* @internal
|
|
@@ -66,7 +66,7 @@ export declare class ConnectionManager extends BaseObserver<ConnectionManagerLis
|
|
|
66
66
|
constructor(options: ConnectionManagerOptions);
|
|
67
67
|
get logger(): ILogger;
|
|
68
68
|
close(): Promise<void>;
|
|
69
|
-
connect(connector: PowerSyncBackendConnector, options
|
|
69
|
+
connect(connector: PowerSyncBackendConnector, options: InternalConnectionOptions): Promise<void>;
|
|
70
70
|
protected connectInternal(): Promise<void>;
|
|
71
71
|
/**
|
|
72
72
|
* Close the sync connection.
|
|
@@ -88,7 +88,8 @@ export interface StreamingSyncImplementationListener extends BaseListener {
|
|
|
88
88
|
* Configurable options to be used when connecting to the PowerSync
|
|
89
89
|
* backend instance.
|
|
90
90
|
*/
|
|
91
|
-
export
|
|
91
|
+
export type PowerSyncConnectionOptions = Omit<InternalConnectionOptions, 'serializedSchema'>;
|
|
92
|
+
export interface InternalConnectionOptions extends BaseConnectionOptions, AdditionalConnectionOptions {
|
|
92
93
|
}
|
|
93
94
|
/** @internal */
|
|
94
95
|
export interface BaseConnectionOptions {
|
|
@@ -114,6 +115,10 @@ export interface BaseConnectionOptions {
|
|
|
114
115
|
* These parameters are passed to the sync rules, and will be available under the`user_parameters` object.
|
|
115
116
|
*/
|
|
116
117
|
params?: Record<string, StreamingSyncRequestParameterType>;
|
|
118
|
+
/**
|
|
119
|
+
* The serialized schema - mainly used to forward information about raw tables to the sync client.
|
|
120
|
+
*/
|
|
121
|
+
serializedSchema?: any;
|
|
117
122
|
}
|
|
118
123
|
/** @internal */
|
|
119
124
|
export interface AdditionalConnectionOptions {
|
|
@@ -135,7 +140,7 @@ export interface StreamingSyncImplementation extends BaseObserverInterface<Strea
|
|
|
135
140
|
/**
|
|
136
141
|
* Connects to the sync service
|
|
137
142
|
*/
|
|
138
|
-
connect(options?:
|
|
143
|
+
connect(options?: InternalConnectionOptions): Promise<void>;
|
|
139
144
|
/**
|
|
140
145
|
* Disconnects from the sync services.
|
|
141
146
|
* @throws if not connected or if abort is not controlled internally
|
|
@@ -72,7 +72,8 @@ export const DEFAULT_STREAM_CONNECTION_OPTIONS = {
|
|
|
72
72
|
connectionMethod: SyncStreamConnectionMethod.WEB_SOCKET,
|
|
73
73
|
clientImplementation: DEFAULT_SYNC_CLIENT_IMPLEMENTATION,
|
|
74
74
|
fetchStrategy: FetchStrategy.Buffered,
|
|
75
|
-
params: {}
|
|
75
|
+
params: {},
|
|
76
|
+
serializedSchema: undefined
|
|
76
77
|
};
|
|
77
78
|
// The priority we assume when we receive checkpoint lines where no priority is set.
|
|
78
79
|
// This is the default priority used by the sync service, but can be set to an arbitrary
|
|
@@ -526,6 +527,8 @@ The next upload iteration will be delayed.`);
|
|
|
526
527
|
}
|
|
527
528
|
if (isStreamingSyncCheckpoint(line)) {
|
|
528
529
|
targetCheckpoint = line.checkpoint;
|
|
530
|
+
// New checkpoint - existing validated checkpoint is no longer valid
|
|
531
|
+
pendingValidatedCheckpoint = null;
|
|
529
532
|
const bucketsToDelete = new Set(bucketMap.keys());
|
|
530
533
|
const newBuckets = new Map();
|
|
531
534
|
for (const checksum of line.checkpoint.buckets) {
|
|
@@ -549,8 +552,15 @@ The next upload iteration will be delayed.`);
|
|
|
549
552
|
return;
|
|
550
553
|
}
|
|
551
554
|
else if (!result.applied) {
|
|
555
|
+
// "Could not apply checkpoint due to local data". We need to retry after
|
|
556
|
+
// finishing uploads.
|
|
552
557
|
pendingValidatedCheckpoint = targetCheckpoint;
|
|
553
558
|
}
|
|
559
|
+
else {
|
|
560
|
+
// Nothing to retry later. This would likely already be null from the last
|
|
561
|
+
// checksum or checksum_diff operation, but we make sure.
|
|
562
|
+
pendingValidatedCheckpoint = null;
|
|
563
|
+
}
|
|
554
564
|
}
|
|
555
565
|
else if (isStreamingSyncCheckpointPartiallyComplete(line)) {
|
|
556
566
|
const priority = line.partial_checkpoint_complete.priority;
|
|
@@ -587,6 +597,8 @@ The next upload iteration will be delayed.`);
|
|
|
587
597
|
if (targetCheckpoint == null) {
|
|
588
598
|
throw new Error('Checkpoint diff without previous checkpoint');
|
|
589
599
|
}
|
|
600
|
+
// New checkpoint - existing validated checkpoint is no longer valid
|
|
601
|
+
pendingValidatedCheckpoint = null;
|
|
590
602
|
const diff = line.checkpoint_diff;
|
|
591
603
|
const newBuckets = new Map();
|
|
592
604
|
for (const checksum of targetCheckpoint.buckets) {
|
|
@@ -826,9 +838,11 @@ The next upload iteration will be delayed.`);
|
|
|
826
838
|
}
|
|
827
839
|
}
|
|
828
840
|
try {
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
841
|
+
const options = { parameters: resolvedOptions.params };
|
|
842
|
+
if (resolvedOptions.serializedSchema) {
|
|
843
|
+
options.schema = resolvedOptions.serializedSchema;
|
|
844
|
+
}
|
|
845
|
+
await control(PowerSyncControlCommand.START, JSON.stringify(options));
|
|
832
846
|
this.notifyCompletedUploads = () => {
|
|
833
847
|
controlInvocations?.enqueueData({ command: PowerSyncControlCommand.NOTIFY_CRUD_UPLOAD_COMPLETED });
|
|
834
848
|
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A pending variant of a {@link RawTable} that doesn't have a name (because it would be inferred when creating the
|
|
3
|
+
* schema).
|
|
4
|
+
*/
|
|
5
|
+
export type RawTableType = {
|
|
6
|
+
/**
|
|
7
|
+
* The statement to run when PowerSync detects that a row needs to be inserted or updated.
|
|
8
|
+
*/
|
|
9
|
+
put: PendingStatement;
|
|
10
|
+
/**
|
|
11
|
+
* The statement to run when PowerSync detects that a row needs to be deleted.
|
|
12
|
+
*/
|
|
13
|
+
delete: PendingStatement;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* A parameter to use as part of {@link PendingStatement}.
|
|
17
|
+
*
|
|
18
|
+
* For delete statements, only the `"Id"` value is supported - the sync client will replace it with the id of the row to
|
|
19
|
+
* be synced.
|
|
20
|
+
*
|
|
21
|
+
* For insert and replace operations, the values of columns in the table are available as parameters through
|
|
22
|
+
* `{Column: 'name'}`.
|
|
23
|
+
*/
|
|
24
|
+
export type PendingStatementParameter = 'Id' | {
|
|
25
|
+
Column: string;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* A statement that the PowerSync client should use to insert or delete data into a table managed by the user.
|
|
29
|
+
*/
|
|
30
|
+
export type PendingStatement = {
|
|
31
|
+
sql: string;
|
|
32
|
+
params: PendingStatementParameter[];
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Instructs PowerSync to sync data into a "raw" table.
|
|
36
|
+
*
|
|
37
|
+
* Since raw tables are not backed by JSON, running complex queries on them may be more efficient. Further, they allow
|
|
38
|
+
* using client-side table and column constraints.
|
|
39
|
+
*
|
|
40
|
+
* Note that raw tables are only supported when using the new `SyncClientImplementation.rust` sync client.
|
|
41
|
+
*
|
|
42
|
+
* @experimental Please note that this feature is experimental at the moment, and not covered by PowerSync semver or
|
|
43
|
+
* stability guarantees.
|
|
44
|
+
*/
|
|
45
|
+
export declare class RawTable implements RawTableType {
|
|
46
|
+
/**
|
|
47
|
+
* The name of the table.
|
|
48
|
+
*
|
|
49
|
+
* This does not have to match the actual table name in the schema - {@link put} and {@link delete} are free to use
|
|
50
|
+
* another table. Instead, this name is used by the sync client to recognize that operations on this table (as it
|
|
51
|
+
* appears in the source / backend database) are to be handled specially.
|
|
52
|
+
*/
|
|
53
|
+
name: string;
|
|
54
|
+
put: PendingStatement;
|
|
55
|
+
delete: PendingStatement;
|
|
56
|
+
constructor(name: string, type: RawTableType);
|
|
57
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Instructs PowerSync to sync data into a "raw" table.
|
|
3
|
+
*
|
|
4
|
+
* Since raw tables are not backed by JSON, running complex queries on them may be more efficient. Further, they allow
|
|
5
|
+
* using client-side table and column constraints.
|
|
6
|
+
*
|
|
7
|
+
* Note that raw tables are only supported when using the new `SyncClientImplementation.rust` sync client.
|
|
8
|
+
*
|
|
9
|
+
* @experimental Please note that this feature is experimental at the moment, and not covered by PowerSync semver or
|
|
10
|
+
* stability guarantees.
|
|
11
|
+
*/
|
|
12
|
+
export class RawTable {
|
|
13
|
+
/**
|
|
14
|
+
* The name of the table.
|
|
15
|
+
*
|
|
16
|
+
* This does not have to match the actual table name in the schema - {@link put} and {@link delete} are free to use
|
|
17
|
+
* another table. Instead, this name is used by the sync client to recognize that operations on this table (as it
|
|
18
|
+
* appears in the source / backend database) are to be handled specially.
|
|
19
|
+
*/
|
|
20
|
+
name;
|
|
21
|
+
put;
|
|
22
|
+
delete;
|
|
23
|
+
constructor(name, type) {
|
|
24
|
+
this.name = name;
|
|
25
|
+
this.put = type.put;
|
|
26
|
+
this.delete = type.delete;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { RawTable, RawTableType } from './RawTable.js';
|
|
1
2
|
import { RowType, Table } from './Table.js';
|
|
2
3
|
type SchemaType = Record<string, Table<any>>;
|
|
3
4
|
export type SchemaTableType<S extends SchemaType> = {
|
|
@@ -10,7 +11,19 @@ export declare class Schema<S extends SchemaType = SchemaType> {
|
|
|
10
11
|
readonly types: SchemaTableType<S>;
|
|
11
12
|
readonly props: S;
|
|
12
13
|
readonly tables: Table[];
|
|
14
|
+
readonly rawTables: RawTable[];
|
|
13
15
|
constructor(tables: Table[] | S);
|
|
16
|
+
/**
|
|
17
|
+
* Adds raw tables to this schema. Raw tables are identified by their name, but entirely managed by the application
|
|
18
|
+
* developer instead of automatically by PowerSync.
|
|
19
|
+
* Since raw tables are not backed by JSON, running complex queries on them may be more efficient. Further, they allow
|
|
20
|
+
* using client-side table and column constraints.
|
|
21
|
+
* Note that raw tables are only supported when using the new `SyncClientImplementation.rust` sync client.
|
|
22
|
+
*
|
|
23
|
+
* @param tables An object of (table name, raw table definition) entries.
|
|
24
|
+
* @experimental Note that the raw tables API is still experimental and may change in the future.
|
|
25
|
+
*/
|
|
26
|
+
withRawTables(tables: Record<string, RawTableType>): void;
|
|
14
27
|
validate(): void;
|
|
15
28
|
toJSON(): {
|
|
16
29
|
tables: {
|
|
@@ -35,6 +48,7 @@ export declare class Schema<S extends SchemaType = SchemaType> {
|
|
|
35
48
|
}[];
|
|
36
49
|
}[];
|
|
37
50
|
}[];
|
|
51
|
+
raw_tables: RawTable[];
|
|
38
52
|
};
|
|
39
53
|
private convertToClassicTables;
|
|
40
54
|
}
|
package/lib/db/schema/Schema.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { RawTable } from './RawTable.js';
|
|
1
2
|
/**
|
|
2
3
|
* A schema is a collection of tables. It is used to define the structure of a database.
|
|
3
4
|
*/
|
|
@@ -8,6 +9,7 @@ export class Schema {
|
|
|
8
9
|
types;
|
|
9
10
|
props;
|
|
10
11
|
tables;
|
|
12
|
+
rawTables;
|
|
11
13
|
constructor(tables) {
|
|
12
14
|
if (Array.isArray(tables)) {
|
|
13
15
|
/*
|
|
@@ -26,6 +28,22 @@ export class Schema {
|
|
|
26
28
|
this.props = tables;
|
|
27
29
|
this.tables = this.convertToClassicTables(this.props);
|
|
28
30
|
}
|
|
31
|
+
this.rawTables = [];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Adds raw tables to this schema. Raw tables are identified by their name, but entirely managed by the application
|
|
35
|
+
* developer instead of automatically by PowerSync.
|
|
36
|
+
* Since raw tables are not backed by JSON, running complex queries on them may be more efficient. Further, they allow
|
|
37
|
+
* using client-side table and column constraints.
|
|
38
|
+
* Note that raw tables are only supported when using the new `SyncClientImplementation.rust` sync client.
|
|
39
|
+
*
|
|
40
|
+
* @param tables An object of (table name, raw table definition) entries.
|
|
41
|
+
* @experimental Note that the raw tables API is still experimental and may change in the future.
|
|
42
|
+
*/
|
|
43
|
+
withRawTables(tables) {
|
|
44
|
+
for (const [name, rawTableDefinition] of Object.entries(tables)) {
|
|
45
|
+
this.rawTables.push(new RawTable(name, rawTableDefinition));
|
|
46
|
+
}
|
|
29
47
|
}
|
|
30
48
|
validate() {
|
|
31
49
|
for (const table of this.tables) {
|
|
@@ -35,7 +53,8 @@ export class Schema {
|
|
|
35
53
|
toJSON() {
|
|
36
54
|
return {
|
|
37
55
|
// This is required because "name" field is not present in TableV2
|
|
38
|
-
tables: this.tables.map((t) => t.toJSON())
|
|
56
|
+
tables: this.tables.map((t) => t.toJSON()),
|
|
57
|
+
raw_tables: this.rawTables
|
|
39
58
|
};
|
|
40
59
|
}
|
|
41
60
|
convertToClassicTables(props) {
|