@powersync/common 1.38.0 → 1.38.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/index.d.cts CHANGED
@@ -1815,12 +1815,14 @@ declare enum WatchedQueryListenerEvent {
1815
1815
  ON_DATA = "onData",
1816
1816
  ON_ERROR = "onError",
1817
1817
  ON_STATE_CHANGE = "onStateChange",
1818
+ SETTINGS_WILL_UPDATE = "settingsWillUpdate",
1818
1819
  CLOSED = "closed"
1819
1820
  }
1820
1821
  interface WatchedQueryListener<Data> extends BaseListener {
1821
1822
  [WatchedQueryListenerEvent.ON_DATA]?: (data: Data) => void | Promise<void>;
1822
1823
  [WatchedQueryListenerEvent.ON_ERROR]?: (error: Error) => void | Promise<void>;
1823
1824
  [WatchedQueryListenerEvent.ON_STATE_CHANGE]?: (state: WatchedQueryState<Data>) => void | Promise<void>;
1825
+ [WatchedQueryListenerEvent.SETTINGS_WILL_UPDATE]?: () => void;
1824
1826
  [WatchedQueryListenerEvent.CLOSED]?: () => void | Promise<void>;
1825
1827
  }
1826
1828
  declare const DEFAULT_WATCH_THROTTLE_MS = 30;
@@ -1886,6 +1888,7 @@ declare abstract class AbstractQueryProcessor<Data = unknown[], Settings extends
1886
1888
  constructor(options: AbstractQueryProcessorOptions<Data, Settings>);
1887
1889
  protected constructInitialState(): WatchedQueryState<Data>;
1888
1890
  protected get reportFetching(): boolean;
1891
+ protected updateSettingsInternal(settings: Settings, signal: AbortSignal): Promise<void>;
1889
1892
  /**
1890
1893
  * Updates the underlying query.
1891
1894
  */
@@ -1899,7 +1902,7 @@ declare abstract class AbstractQueryProcessor<Data = unknown[], Settings extends
1899
1902
  /**
1900
1903
  * Configures base DB listeners and links the query to listeners.
1901
1904
  */
1902
- protected init(): Promise<void>;
1905
+ protected init(signal: AbortSignal): Promise<void>;
1903
1906
  close(): Promise<void>;
1904
1907
  /**
1905
1908
  * Runs a callback and reports errors to the error listeners.
@@ -2549,7 +2552,7 @@ interface TriggerManager {
2549
2552
  * },
2550
2553
  * onChange: async (context) => {
2551
2554
  * // Fetches the todo records that were inserted during this diff
2552
- * const newTodos = await context.getAll<Database['todos']>(`
2555
+ * const newTodos = await context.withDiff<Database['todos']>(`
2553
2556
  * SELECT
2554
2557
  * todos.*
2555
2558
  * FROM
@@ -323,7 +323,7 @@ export interface TriggerManager {
323
323
  * },
324
324
  * onChange: async (context) => {
325
325
  * // Fetches the todo records that were inserted during this diff
326
- * const newTodos = await context.getAll<Database['todos']>(`
326
+ * const newTodos = await context.withDiff<Database['todos']>(`
327
327
  * SELECT
328
328
  * todos.*
329
329
  * FROM
@@ -65,12 +65,14 @@ export declare enum WatchedQueryListenerEvent {
65
65
  ON_DATA = "onData",
66
66
  ON_ERROR = "onError",
67
67
  ON_STATE_CHANGE = "onStateChange",
68
+ SETTINGS_WILL_UPDATE = "settingsWillUpdate",
68
69
  CLOSED = "closed"
69
70
  }
70
71
  export interface WatchedQueryListener<Data> extends BaseListener {
71
72
  [WatchedQueryListenerEvent.ON_DATA]?: (data: Data) => void | Promise<void>;
72
73
  [WatchedQueryListenerEvent.ON_ERROR]?: (error: Error) => void | Promise<void>;
73
74
  [WatchedQueryListenerEvent.ON_STATE_CHANGE]?: (state: WatchedQueryState<Data>) => void | Promise<void>;
75
+ [WatchedQueryListenerEvent.SETTINGS_WILL_UPDATE]?: () => void;
74
76
  [WatchedQueryListenerEvent.CLOSED]?: () => void | Promise<void>;
75
77
  }
76
78
  export declare const DEFAULT_WATCH_THROTTLE_MS = 30;
@@ -3,6 +3,7 @@ export var WatchedQueryListenerEvent;
3
3
  WatchedQueryListenerEvent["ON_DATA"] = "onData";
4
4
  WatchedQueryListenerEvent["ON_ERROR"] = "onError";
5
5
  WatchedQueryListenerEvent["ON_STATE_CHANGE"] = "onStateChange";
6
+ WatchedQueryListenerEvent["SETTINGS_WILL_UPDATE"] = "settingsWillUpdate";
6
7
  WatchedQueryListenerEvent["CLOSED"] = "closed";
7
8
  })(WatchedQueryListenerEvent || (WatchedQueryListenerEvent = {}));
8
9
  export const DEFAULT_WATCH_THROTTLE_MS = 30;
@@ -40,6 +40,7 @@ export declare abstract class AbstractQueryProcessor<Data = unknown[], Settings
40
40
  constructor(options: AbstractQueryProcessorOptions<Data, Settings>);
41
41
  protected constructInitialState(): WatchedQueryState<Data>;
42
42
  protected get reportFetching(): boolean;
43
+ protected updateSettingsInternal(settings: Settings, signal: AbortSignal): Promise<void>;
43
44
  /**
44
45
  * Updates the underlying query.
45
46
  */
@@ -53,7 +54,7 @@ export declare abstract class AbstractQueryProcessor<Data = unknown[], Settings
53
54
  /**
54
55
  * Configures base DB listeners and links the query to listeners.
55
56
  */
56
- protected init(): Promise<void>;
57
+ protected init(signal: AbortSignal): Promise<void>;
57
58
  close(): Promise<void>;
58
59
  /**
59
60
  * Runs a callback and reports errors to the error listeners.
@@ -1,4 +1,5 @@
1
1
  import { MetaBaseObserver } from '../../../utils/MetaBaseObserver.js';
2
+ import { WatchedQueryListenerEvent } from '../WatchedQuery.js';
2
3
  /**
3
4
  * Performs underlying watching and yields a stream of results.
4
5
  * @internal
@@ -20,7 +21,7 @@ export class AbstractQueryProcessor extends MetaBaseObserver {
20
21
  this._closed = false;
21
22
  this.state = this.constructInitialState();
22
23
  this.disposeListeners = null;
23
- this.initialized = this.init();
24
+ this.initialized = this.init(this.abortController.signal);
24
25
  }
25
26
  constructInitialState() {
26
27
  return {
@@ -34,25 +35,40 @@ export class AbstractQueryProcessor extends MetaBaseObserver {
34
35
  get reportFetching() {
35
36
  return this.options.watchOptions.reportFetching ?? true;
36
37
  }
37
- /**
38
- * Updates the underlying query.
39
- */
40
- async updateSettings(settings) {
41
- this.abortController.abort();
42
- await this.initialized;
38
+ async updateSettingsInternal(settings, signal) {
39
+ // This may have been aborted while awaiting or if multiple calls to `updateSettings` were made
40
+ if (this._closed || signal.aborted) {
41
+ return;
42
+ }
43
+ this.options.watchOptions = settings;
44
+ this.iterateListeners((l) => l[WatchedQueryListenerEvent.SETTINGS_WILL_UPDATE]?.());
43
45
  if (!this.state.isFetching && this.reportFetching) {
44
46
  await this.updateState({
45
47
  isFetching: true
46
48
  });
47
49
  }
48
- this.options.watchOptions = settings;
49
- this.abortController = new AbortController();
50
50
  await this.runWithReporting(() => this.linkQuery({
51
- abortSignal: this.abortController.signal,
51
+ abortSignal: signal,
52
52
  settings
53
53
  }));
54
54
  }
55
+ /**
56
+ * Updates the underlying query.
57
+ */
58
+ async updateSettings(settings) {
59
+ // Abort the previous request
60
+ this.abortController.abort();
61
+ // Keep track of this controller's abort status
62
+ const abortController = new AbortController();
63
+ // Allow this to be aborted externally
64
+ this.abortController = abortController;
65
+ await this.initialized;
66
+ return this.updateSettingsInternal(settings, abortController.signal);
67
+ }
55
68
  async updateState(update) {
69
+ if (this._closed) {
70
+ return;
71
+ }
56
72
  if (typeof update.error !== 'undefined') {
57
73
  await this.iterateAsyncListenersWithError(async (l) => l.onError?.(update.error));
58
74
  // An error always stops for the current fetching state
@@ -68,7 +84,7 @@ export class AbstractQueryProcessor extends MetaBaseObserver {
68
84
  /**
69
85
  * Configures base DB listeners and links the query to listeners.
70
86
  */
71
- async init() {
87
+ async init(signal) {
72
88
  const { db } = this.options;
73
89
  const disposeCloseListener = db.registerListener({
74
90
  closing: async () => {
@@ -89,16 +105,15 @@ export class AbstractQueryProcessor extends MetaBaseObserver {
89
105
  disposeSchemaListener();
90
106
  };
91
107
  // Initial setup
92
- this.runWithReporting(async () => {
93
- await this.updateSettings(this.options.watchOptions);
108
+ await this.runWithReporting(async () => {
109
+ await this.updateSettingsInternal(this.options.watchOptions, signal);
94
110
  });
95
111
  }
96
112
  async close() {
97
- await this.initialized;
113
+ this._closed = true;
98
114
  this.abortController.abort();
99
115
  this.disposeListeners?.();
100
116
  this.disposeListeners = null;
101
- this._closed = true;
102
117
  this.iterateListeners((l) => l.closed?.());
103
118
  this.listeners.clear();
104
119
  }
@@ -148,6 +148,9 @@ export class DifferentialQueryProcessor extends AbstractQueryProcessor {
148
148
  data: diff.all
149
149
  });
150
150
  }
151
+ if (this.state.error) {
152
+ partialStateUpdate.error = null;
153
+ }
151
154
  if (Object.keys(partialStateUpdate).length > 0) {
152
155
  await this.updateState(partialStateUpdate);
153
156
  }
@@ -58,6 +58,9 @@ export class OnChangeQueryProcessor extends AbstractQueryProcessor {
58
58
  data: result
59
59
  });
60
60
  }
61
+ if (this.state.error) {
62
+ partialStateUpdate.error = null;
63
+ }
61
64
  if (Object.keys(partialStateUpdate).length > 0) {
62
65
  await this.updateState(partialStateUpdate);
63
66
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@powersync/common",
3
- "version": "1.38.0",
3
+ "version": "1.38.1",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "public"