@powersync/web 1.27.1 → 1.28.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.
Files changed (40) hide show
  1. package/dist/index.umd.js +64 -26
  2. package/dist/index.umd.js.map +1 -1
  3. package/dist/worker/SharedSyncImplementation.umd.js +13640 -440
  4. package/dist/worker/SharedSyncImplementation.umd.js.map +1 -1
  5. package/dist/worker/WASQLiteDB.umd.js +13467 -161
  6. package/dist/worker/WASQLiteDB.umd.js.map +1 -1
  7. package/dist/worker/node_modules_bson_lib_bson_mjs.umd.js +66 -38
  8. package/dist/worker/node_modules_bson_lib_bson_mjs.umd.js.map +1 -1
  9. package/lib/package.json +6 -5
  10. package/lib/tsconfig.tsbuildinfo +1 -1
  11. package/package.json +7 -6
  12. package/src/db/PowerSyncDatabase.ts +224 -0
  13. package/src/db/adapters/AbstractWebPowerSyncDatabaseOpenFactory.ts +47 -0
  14. package/src/db/adapters/AbstractWebSQLOpenFactory.ts +48 -0
  15. package/src/db/adapters/AsyncDatabaseConnection.ts +40 -0
  16. package/src/db/adapters/LockedAsyncDatabaseAdapter.ts +358 -0
  17. package/src/db/adapters/SSRDBAdapter.ts +94 -0
  18. package/src/db/adapters/WebDBAdapter.ts +20 -0
  19. package/src/db/adapters/WorkerWrappedAsyncDatabaseConnection.ts +175 -0
  20. package/src/db/adapters/wa-sqlite/WASQLiteConnection.ts +444 -0
  21. package/src/db/adapters/wa-sqlite/WASQLiteDBAdapter.ts +86 -0
  22. package/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.ts +134 -0
  23. package/src/db/adapters/wa-sqlite/WASQLitePowerSyncDatabaseOpenFactory.ts +24 -0
  24. package/src/db/adapters/web-sql-flags.ts +135 -0
  25. package/src/db/sync/SSRWebStreamingSyncImplementation.ts +89 -0
  26. package/src/db/sync/SharedWebStreamingSyncImplementation.ts +274 -0
  27. package/src/db/sync/WebRemote.ts +59 -0
  28. package/src/db/sync/WebStreamingSyncImplementation.ts +34 -0
  29. package/src/db/sync/userAgent.ts +78 -0
  30. package/src/index.ts +13 -0
  31. package/src/shared/navigator.ts +9 -0
  32. package/src/worker/db/WASQLiteDB.worker.ts +112 -0
  33. package/src/worker/db/open-worker-database.ts +62 -0
  34. package/src/worker/sync/AbstractSharedSyncClientProvider.ts +21 -0
  35. package/src/worker/sync/BroadcastLogger.ts +142 -0
  36. package/src/worker/sync/SharedSyncImplementation.ts +520 -0
  37. package/src/worker/sync/SharedSyncImplementation.worker.ts +14 -0
  38. package/src/worker/sync/WorkerClient.ts +106 -0
  39. package/dist/worker/node_modules_crypto-browserify_index_js.umd.js +0 -33734
  40. package/dist/worker/node_modules_crypto-browserify_index_js.umd.js.map +0 -1
@@ -0,0 +1,224 @@
1
+ import {
2
+ type BucketStorageAdapter,
3
+ type PowerSyncBackendConnector,
4
+ type PowerSyncCloseOptions,
5
+ type RequiredAdditionalConnectionOptions,
6
+ AbstractPowerSyncDatabase,
7
+ DBAdapter,
8
+ DEFAULT_POWERSYNC_CLOSE_OPTIONS,
9
+ isDBAdapter,
10
+ isSQLOpenFactory,
11
+ PowerSyncDatabaseOptions,
12
+ PowerSyncDatabaseOptionsWithDBAdapter,
13
+ PowerSyncDatabaseOptionsWithOpenFactory,
14
+ PowerSyncDatabaseOptionsWithSettings,
15
+ SqliteBucketStorage,
16
+ StreamingSyncImplementation
17
+ } from '@powersync/common';
18
+ import { Mutex } from 'async-mutex';
19
+ import { getNavigatorLocks } from '../shared/navigator';
20
+ import { WASQLiteOpenFactory } from './adapters/wa-sqlite/WASQLiteOpenFactory';
21
+ import {
22
+ DEFAULT_WEB_SQL_FLAGS,
23
+ ResolvedWebSQLOpenOptions,
24
+ resolveWebSQLFlags,
25
+ WebSQLFlags
26
+ } from './adapters/web-sql-flags';
27
+ import { WebDBAdapter } from './adapters/WebDBAdapter';
28
+ import { SharedWebStreamingSyncImplementation } from './sync/SharedWebStreamingSyncImplementation';
29
+ import { SSRStreamingSyncImplementation } from './sync/SSRWebStreamingSyncImplementation';
30
+ import { WebRemote } from './sync/WebRemote';
31
+ import {
32
+ WebStreamingSyncImplementation,
33
+ WebStreamingSyncImplementationOptions
34
+ } from './sync/WebStreamingSyncImplementation';
35
+
36
+ export interface WebPowerSyncFlags extends WebSQLFlags {
37
+ /**
38
+ * Externally unload open PowerSync database instances when the window closes.
39
+ * Setting this to `true` requires calling `close` on all open PowerSyncDatabase
40
+ * instances before the window unloads
41
+ */
42
+ externallyUnload?: boolean;
43
+ }
44
+
45
+ type WithWebFlags<Base> = Base & { flags?: WebPowerSyncFlags };
46
+
47
+ export interface WebSyncOptions {
48
+ /**
49
+ * Allows you to override the default sync worker.
50
+ *
51
+ * You can either provide a path to the worker script
52
+ * or a factory method that returns a worker.
53
+ */
54
+ worker?: string | URL | ((options: ResolvedWebSQLOpenOptions) => SharedWorker);
55
+ }
56
+
57
+ type WithWebSyncOptions<Base> = Base & {
58
+ sync?: WebSyncOptions;
59
+ };
60
+
61
+ export interface WebEncryptionOptions {
62
+ /**
63
+ * Encryption key for the database.
64
+ * If set, the database will be encrypted using Multiple Ciphers.
65
+ */
66
+ encryptionKey?: string;
67
+ }
68
+
69
+ type WithWebEncryptionOptions<Base> = Base & WebEncryptionOptions;
70
+
71
+ export type WebPowerSyncDatabaseOptionsWithAdapter = WithWebSyncOptions<
72
+ WithWebFlags<PowerSyncDatabaseOptionsWithDBAdapter>
73
+ >;
74
+ export type WebPowerSyncDatabaseOptionsWithOpenFactory = WithWebSyncOptions<
75
+ WithWebFlags<PowerSyncDatabaseOptionsWithOpenFactory>
76
+ >;
77
+ export type WebPowerSyncDatabaseOptionsWithSettings = WithWebSyncOptions<
78
+ WithWebFlags<WithWebEncryptionOptions<PowerSyncDatabaseOptionsWithSettings>>
79
+ >;
80
+
81
+ export type WebPowerSyncDatabaseOptions = WithWebSyncOptions<WithWebFlags<PowerSyncDatabaseOptions>>;
82
+
83
+ export const DEFAULT_POWERSYNC_FLAGS: Required<WebPowerSyncFlags> = {
84
+ ...DEFAULT_WEB_SQL_FLAGS,
85
+ externallyUnload: false
86
+ };
87
+
88
+ export const resolveWebPowerSyncFlags = (flags?: WebPowerSyncFlags): Required<WebPowerSyncFlags> => {
89
+ return {
90
+ ...DEFAULT_POWERSYNC_FLAGS,
91
+ ...flags,
92
+ ...resolveWebSQLFlags(flags)
93
+ };
94
+ };
95
+
96
+ /**
97
+ * Asserts that the database options are valid for custom database constructors.
98
+ */
99
+ function assertValidDatabaseOptions(options: WebPowerSyncDatabaseOptions): void {
100
+ if ('database' in options && 'encryptionKey' in options) {
101
+ const { database } = options;
102
+ if (isSQLOpenFactory(database) || isDBAdapter(database)) {
103
+ throw new Error(
104
+ `Invalid configuration: 'encryptionKey' should only be included inside the database object when using a custom ${isSQLOpenFactory(database) ? 'WASQLiteOpenFactory' : 'WASQLiteDBAdapter'} constructor.`
105
+ );
106
+ }
107
+ }
108
+ }
109
+
110
+ /**
111
+ * A PowerSync database which provides SQLite functionality
112
+ * which is automatically synced.
113
+ *
114
+ * @example
115
+ * ```typescript
116
+ * export const db = new PowerSyncDatabase({
117
+ * schema: AppSchema,
118
+ * database: {
119
+ * dbFilename: 'example.db'
120
+ * }
121
+ * });
122
+ * ```
123
+ */
124
+ export class PowerSyncDatabase extends AbstractPowerSyncDatabase {
125
+ static SHARED_MUTEX = new Mutex();
126
+
127
+ protected unloadListener?: () => Promise<void>;
128
+ protected resolvedFlags: WebPowerSyncFlags;
129
+
130
+ constructor(options: WebPowerSyncDatabaseOptionsWithAdapter);
131
+ constructor(options: WebPowerSyncDatabaseOptionsWithOpenFactory);
132
+ constructor(options: WebPowerSyncDatabaseOptionsWithSettings);
133
+ constructor(options: WebPowerSyncDatabaseOptions);
134
+ constructor(protected options: WebPowerSyncDatabaseOptions) {
135
+ super(options);
136
+
137
+ assertValidDatabaseOptions(options);
138
+
139
+ this.resolvedFlags = resolveWebPowerSyncFlags(options.flags);
140
+
141
+ if (this.resolvedFlags.enableMultiTabs && !this.resolvedFlags.externallyUnload) {
142
+ this.unloadListener = () => this.close({ disconnect: false });
143
+ window.addEventListener('unload', this.unloadListener);
144
+ }
145
+ }
146
+
147
+ async _initialize(): Promise<void> {}
148
+
149
+ protected openDBAdapter(options: WebPowerSyncDatabaseOptionsWithSettings): DBAdapter {
150
+ const defaultFactory = new WASQLiteOpenFactory({
151
+ ...options.database,
152
+ flags: resolveWebPowerSyncFlags(options.flags),
153
+ encryptionKey: options.encryptionKey
154
+ });
155
+ return defaultFactory.openDB();
156
+ }
157
+
158
+ /**
159
+ * Closes the database connection.
160
+ * By default the sync stream client is only disconnected if
161
+ * multiple tabs are not enabled.
162
+ */
163
+ close(options: PowerSyncCloseOptions = DEFAULT_POWERSYNC_CLOSE_OPTIONS): Promise<void> {
164
+ if (this.unloadListener) {
165
+ window.removeEventListener('unload', this.unloadListener);
166
+ }
167
+
168
+ return super.close({
169
+ // Don't disconnect by default if multiple tabs are enabled
170
+ disconnect: options.disconnect ?? !this.resolvedFlags.enableMultiTabs
171
+ });
172
+ }
173
+
174
+ protected generateBucketStorageAdapter(): BucketStorageAdapter {
175
+ return new SqliteBucketStorage(this.database);
176
+ }
177
+
178
+ protected async runExclusive<T>(cb: () => Promise<T>) {
179
+ if (this.resolvedFlags.ssrMode) {
180
+ return PowerSyncDatabase.SHARED_MUTEX.runExclusive(cb);
181
+ }
182
+ return getNavigatorLocks().request(`lock-${this.database.name}`, cb);
183
+ }
184
+
185
+ protected generateSyncStreamImplementation(
186
+ connector: PowerSyncBackendConnector,
187
+ options: RequiredAdditionalConnectionOptions
188
+ ): StreamingSyncImplementation {
189
+ const remote = new WebRemote(connector, this.logger);
190
+ const syncOptions: WebStreamingSyncImplementationOptions = {
191
+ ...(this.options as {}),
192
+ ...options,
193
+ flags: this.resolvedFlags,
194
+ adapter: this.bucketStorageAdapter,
195
+ remote,
196
+ uploadCrud: async () => {
197
+ await this.waitForReady();
198
+ await connector.uploadData(this);
199
+ },
200
+ identifier: this.database.name,
201
+ logger: this.logger
202
+ };
203
+
204
+ switch (true) {
205
+ case this.resolvedFlags.ssrMode:
206
+ return new SSRStreamingSyncImplementation(syncOptions);
207
+ case this.resolvedFlags.enableMultiTabs:
208
+ if (!this.resolvedFlags.broadcastLogs) {
209
+ const warning = `
210
+ Multiple tabs are enabled, but broadcasting of logs is disabled.
211
+ Logs for shared sync worker will only be available in the shared worker context
212
+ `;
213
+ const logger = this.options.logger;
214
+ logger ? logger.warn(warning) : console.warn(warning);
215
+ }
216
+ return new SharedWebStreamingSyncImplementation({
217
+ ...syncOptions,
218
+ db: this.database as WebDBAdapter // This should always be the case
219
+ });
220
+ default:
221
+ return new WebStreamingSyncImplementation(syncOptions);
222
+ }
223
+ }
224
+ }
@@ -0,0 +1,47 @@
1
+ import {
2
+ AbstractPowerSyncDatabase,
3
+ AbstractPowerSyncDatabaseOpenFactory,
4
+ PowerSyncDatabaseOptions,
5
+ PowerSyncOpenFactoryOptions
6
+ } from '@powersync/common';
7
+ import {
8
+ PowerSyncDatabase,
9
+ WebPowerSyncDatabaseOptions,
10
+ WebPowerSyncFlags,
11
+ resolveWebPowerSyncFlags
12
+ } from '../../db/PowerSyncDatabase';
13
+
14
+ /**
15
+ * {@link WebPowerSyncFlags}
16
+ * Maintaining export for consistency with API from previous versions
17
+ * */
18
+ export interface WebPowerSyncOpenFlags extends WebPowerSyncFlags {}
19
+
20
+ export interface WebPowerSyncOpenFactoryOptions extends PowerSyncOpenFactoryOptions {
21
+ flags?: WebPowerSyncOpenFlags;
22
+ }
23
+
24
+ /**
25
+ * Intermediate PowerSync Database Open factory for Web which uses a mock
26
+ * SSR DB Adapter if running on server side.
27
+ * Most SQLite DB implementations only run on client side, this will safely return
28
+ * empty query results in SSR which will allow for generating server partial views.
29
+ */
30
+ export abstract class AbstractWebPowerSyncDatabaseOpenFactory extends AbstractPowerSyncDatabaseOpenFactory {
31
+ constructor(protected options: WebPowerSyncOpenFactoryOptions) {
32
+ super(options);
33
+ }
34
+
35
+ generateOptions(): WebPowerSyncDatabaseOptions {
36
+ return {
37
+ ...this.options,
38
+ database: this.openDB(),
39
+ schema: this.schema,
40
+ flags: resolveWebPowerSyncFlags(this.options.flags)
41
+ };
42
+ }
43
+
44
+ generateInstance(options: PowerSyncDatabaseOptions): AbstractPowerSyncDatabase {
45
+ return new PowerSyncDatabase(options);
46
+ }
47
+ }
@@ -0,0 +1,48 @@
1
+ import { type ILogger, createLogger, DBAdapter, SQLOpenFactory } from '@powersync/common';
2
+ import { SSRDBAdapter } from './SSRDBAdapter';
3
+ import { ResolvedWebSQLFlags, WebSQLOpenFactoryOptions, isServerSide, resolveWebSQLFlags } from './web-sql-flags';
4
+
5
+ export abstract class AbstractWebSQLOpenFactory implements SQLOpenFactory {
6
+ protected resolvedFlags: ResolvedWebSQLFlags;
7
+ protected logger: ILogger;
8
+
9
+ constructor(protected options: WebSQLOpenFactoryOptions) {
10
+ this.resolvedFlags = resolveWebSQLFlags(options.flags);
11
+ this.logger = options.logger ?? createLogger(`AbstractWebSQLOpenFactory - ${this.options.dbFilename}`);
12
+ }
13
+
14
+ /**
15
+ * Opens a DBAdapter if not in SSR mode
16
+ */
17
+ protected abstract openAdapter(): DBAdapter;
18
+
19
+ /**
20
+ * Opens a {@link DBAdapter} using resolved flags.
21
+ * A SSR implementation is loaded if SSR mode is detected.
22
+ */
23
+ openDB() {
24
+ const {
25
+ resolvedFlags: { disableSSRWarning, enableMultiTabs, ssrMode = isServerSide() }
26
+ } = this;
27
+ if (ssrMode && !disableSSRWarning) {
28
+ this.logger.warn(
29
+ `
30
+ Running PowerSync in SSR mode.
31
+ Only empty query results will be returned.
32
+ Disable this warning by setting 'disableSSRWarning: true' in options.`
33
+ );
34
+ }
35
+
36
+ if (!enableMultiTabs) {
37
+ this.logger.warn(
38
+ 'Multiple tab support is not enabled. Using this site across multiple tabs may not function correctly.'
39
+ );
40
+ }
41
+
42
+ if (ssrMode) {
43
+ return new SSRDBAdapter();
44
+ }
45
+
46
+ return this.openAdapter();
47
+ }
48
+ }
@@ -0,0 +1,40 @@
1
+ import { BatchedUpdateNotification, QueryResult } from '@powersync/common';
2
+ import { ResolvedWebSQLOpenOptions } from './web-sql-flags';
3
+
4
+ /**
5
+ * @internal
6
+ * Proxied query result does not contain a function for accessing row values
7
+ */
8
+ export type ProxiedQueryResult = Omit<QueryResult, 'rows'> & {
9
+ rows: {
10
+ _array: any[];
11
+ length: number;
12
+ };
13
+ };
14
+
15
+ /**
16
+ * @internal
17
+ */
18
+ export type OnTableChangeCallback = (event: BatchedUpdateNotification) => void;
19
+
20
+ /**
21
+ * @internal
22
+ * An async Database connection which provides basic async SQL methods.
23
+ * This is usually a proxied through a web worker.
24
+ */
25
+ export interface AsyncDatabaseConnection<Config extends ResolvedWebSQLOpenOptions = ResolvedWebSQLOpenOptions> {
26
+ init(): Promise<void>;
27
+ close(): Promise<void>;
28
+ execute(sql: string, params?: any[]): Promise<ProxiedQueryResult>;
29
+ executeRaw(sql: string, params?: any[]): Promise<any[][]>;
30
+ executeBatch(sql: string, params?: any[]): Promise<ProxiedQueryResult>;
31
+ registerOnTableChange(callback: OnTableChangeCallback): Promise<() => void>;
32
+ getConfig(): Promise<Config>;
33
+ }
34
+
35
+ /**
36
+ * @internal
37
+ */
38
+ export type OpenAsyncDatabaseConnection<Config extends ResolvedWebSQLOpenOptions = ResolvedWebSQLOpenOptions> = (
39
+ config: Config
40
+ ) => AsyncDatabaseConnection;