@powersync/node 0.2.2 → 0.4.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.
package/README.md CHANGED
@@ -56,6 +56,22 @@ contains everything you need to know to get started implementing PowerSync in yo
56
56
 
57
57
  A simple example using `@powersync/node` is available in the [`demos/example-node/`](../demos/example-node) directory.
58
58
 
59
+ # Proxy Support
60
+
61
+ This SDK supports HTTP, HTTPS, and WebSocket proxies via environment variables.
62
+
63
+ ## HTTP Connection Method
64
+
65
+ Internally we probe the http environment variables and apply it to fetch requests ([undici](https://www.npmjs.com/package/undici/v/5.6.0))
66
+
67
+ - Set the `HTTPS_PROXY` or `HTTP_PROXY` environment variable to automatically route HTTP requests through a proxy.
68
+
69
+ ## WEB Socket Connection Method
70
+
71
+ Internally the [proxy-agent](https://www.npmjs.com/package/proxy-agent) dependency for WebSocket proxies, which has its own internal code for automatically picking up the appropriate environment variables:
72
+
73
+ - Set the `WS_PROXY` or `WSS_PROXY` environment variable to route the webocket connections through a proxy.
74
+
59
75
  # Found a bug or need help?
60
76
 
61
77
  - Join our [Discord server](https://discord.gg/powersync) where you can browse topics from our community, ask questions, share feedback, or just say hello :)
package/download_core.js CHANGED
@@ -6,7 +6,7 @@ import { Readable } from 'node:stream';
6
6
  import { finished } from 'node:stream/promises';
7
7
  import { exit } from 'node:process';
8
8
 
9
- const version = '0.3.11';
9
+ const version = '0.3.14';
10
10
 
11
11
  const platform = OS.platform();
12
12
  let destination;
@@ -1,8 +1,23 @@
1
- import { AbstractPowerSyncDatabase, AbstractStreamingSyncImplementation, BucketStorageAdapter, DBAdapter, PowerSyncBackendConnector, PowerSyncDatabaseOptions, PowerSyncDatabaseOptionsWithSettings, SQLOpenFactory } from '@powersync/common';
1
+ import { AbstractPowerSyncDatabase, AbstractRemoteOptions, AbstractStreamingSyncImplementation, AdditionalConnectionOptions, BucketStorageAdapter, DBAdapter, PowerSyncBackendConnector, PowerSyncConnectionOptions, PowerSyncDatabaseOptions, PowerSyncDatabaseOptionsWithSettings, SQLOpenFactory } from '@powersync/common';
2
2
  import { NodeSQLOpenOptions } from './options.js';
3
+ import { Dispatcher } from 'undici';
3
4
  export type NodePowerSyncDatabaseOptions = PowerSyncDatabaseOptions & {
4
5
  database: DBAdapter | SQLOpenFactory | NodeSQLOpenOptions;
6
+ /**
7
+ * Options to override how the SDK will connect to the sync service.
8
+ *
9
+ * This option is intended to be used for internal tests.
10
+ */
11
+ remoteOptions?: Partial<AbstractRemoteOptions>;
12
+ };
13
+ export type NodeAdditionalConnectionOptions = AdditionalConnectionOptions & {
14
+ /**
15
+ * Optional custom dispatcher for HTTP connections (e.g. using undici).
16
+ * Only used when the connection method is SyncStreamConnectionMethod.HTTP
17
+ */
18
+ dispatcher?: Dispatcher;
5
19
  };
20
+ export type NodePowerSyncConnectionOptions = PowerSyncConnectionOptions & NodeAdditionalConnectionOptions;
6
21
  /**
7
22
  * A PowerSync database which provides SQLite functionality
8
23
  * which is automatically synced.
@@ -25,5 +40,8 @@ export declare class PowerSyncDatabase extends AbstractPowerSyncDatabase {
25
40
  */
26
41
  protected openDBAdapter(options: PowerSyncDatabaseOptionsWithSettings): DBAdapter;
27
42
  protected generateBucketStorageAdapter(): BucketStorageAdapter;
28
- protected generateSyncStreamImplementation(connector: PowerSyncBackendConnector): AbstractStreamingSyncImplementation;
43
+ connect(connector: PowerSyncBackendConnector, options?: PowerSyncConnectionOptions & {
44
+ dispatcher?: Dispatcher;
45
+ }): Promise<void>;
46
+ protected generateSyncStreamImplementation(connector: PowerSyncBackendConnector, options: NodeAdditionalConnectionOptions): AbstractStreamingSyncImplementation;
29
47
  }
@@ -32,8 +32,14 @@ export class PowerSyncDatabase extends AbstractPowerSyncDatabase {
32
32
  generateBucketStorageAdapter() {
33
33
  return new SqliteBucketStorage(this.database, AbstractPowerSyncDatabase.transactionMutex);
34
34
  }
35
- generateSyncStreamImplementation(connector) {
36
- const remote = new NodeRemote(connector);
35
+ connect(connector, options) {
36
+ return super.connect(connector, options);
37
+ }
38
+ generateSyncStreamImplementation(connector, options) {
39
+ const remote = new NodeRemote(connector, this.options.logger, {
40
+ dispatcher: options.dispatcher,
41
+ ...this.options.remoteOptions
42
+ });
37
43
  return new NodeStreamingSyncImplementation({
38
44
  adapter: this.bucketStorageAdapter,
39
45
  remote,
@@ -11,6 +11,11 @@ export declare class RemoteConnection implements LockContext {
11
11
  private readonly comlink;
12
12
  readonly database: Remote<AsyncDatabase>;
13
13
  constructor(worker: Worker, comlink: Remote<AsyncDatabaseOpener>, database: Remote<AsyncDatabase>);
14
+ /**
15
+ * Runs the inner function, but appends the stack trace where this function was called. This is useful for workers
16
+ * because stack traces from worker errors are otherwise unrelated to the application issue that has caused them.
17
+ */
18
+ private recoverTrace;
14
19
  executeBatch(query: string, params?: any[][]): Promise<QueryResult>;
15
20
  execute(query: string, params?: any[] | undefined): Promise<QueryResult>;
16
21
  executeRaw(query: string, params?: any[] | undefined): Promise<any[][]>;
@@ -12,16 +12,39 @@ export class RemoteConnection {
12
12
  this.comlink = comlink;
13
13
  this.database = database;
14
14
  }
15
- async executeBatch(query, params = []) {
16
- const result = await this.database.executeBatch(query, params ?? []);
17
- return RemoteConnection.wrapQueryResult(result);
15
+ /**
16
+ * Runs the inner function, but appends the stack trace where this function was called. This is useful for workers
17
+ * because stack traces from worker errors are otherwise unrelated to the application issue that has caused them.
18
+ */
19
+ async recoverTrace(inner) {
20
+ const trace = {};
21
+ Error.captureStackTrace(trace);
22
+ try {
23
+ return await inner();
24
+ }
25
+ catch (e) {
26
+ if (e instanceof Error && e.stack) {
27
+ e.stack += trace.stack;
28
+ }
29
+ throw e;
30
+ }
31
+ }
32
+ executeBatch(query, params = []) {
33
+ return this.recoverTrace(async () => {
34
+ const result = await this.database.executeBatch(query, params ?? []);
35
+ return RemoteConnection.wrapQueryResult(result);
36
+ });
18
37
  }
19
- async execute(query, params) {
20
- const result = await this.database.execute(query, params ?? []);
21
- return RemoteConnection.wrapQueryResult(result);
38
+ execute(query, params) {
39
+ return this.recoverTrace(async () => {
40
+ const result = await this.database.execute(query, params ?? []);
41
+ return RemoteConnection.wrapQueryResult(result);
42
+ });
22
43
  }
23
- async executeRaw(query, params) {
24
- return await this.database.executeRaw(query, params ?? []);
44
+ executeRaw(query, params) {
45
+ return this.recoverTrace(async () => {
46
+ return await this.database.executeRaw(query, params ?? []);
47
+ });
25
48
  }
26
49
  async getAll(sql, parameters) {
27
50
  const res = await this.execute(sql, parameters);
Binary file
@@ -1,10 +1,14 @@
1
- import { ILogger } from 'js-logger';
2
- import { AbstractRemote, AbstractRemoteOptions, BSONImplementation, RemoteConnector } from '@powersync/common';
1
+ import { type ILogger, AbstractRemote, AbstractRemoteOptions, BSONImplementation, RemoteConnector } from '@powersync/common';
2
+ import { Dispatcher } from 'undici';
3
3
  export declare const STREAMING_POST_TIMEOUT_MS = 30000;
4
+ export type NodeRemoteOptions = AbstractRemoteOptions & {
5
+ dispatcher?: Dispatcher;
6
+ };
4
7
  export declare class NodeRemote extends AbstractRemote {
5
8
  protected connector: RemoteConnector;
6
9
  protected logger: ILogger;
7
- constructor(connector: RemoteConnector, logger?: ILogger, options?: Partial<AbstractRemoteOptions>);
10
+ constructor(connector: RemoteConnector, logger?: ILogger, options?: Partial<NodeRemoteOptions>);
11
+ protected createSocket(url: string): globalThis.WebSocket;
8
12
  getUserAgent(): string;
9
13
  getBSON(): Promise<BSONImplementation>;
10
14
  }
@@ -1,6 +1,9 @@
1
1
  import * as os from 'node:os';
2
2
  import { AbstractRemote, DEFAULT_REMOTE_LOGGER, FetchImplementationProvider } from '@powersync/common';
3
3
  import { BSON } from 'bson';
4
+ import Agent from 'proxy-agent';
5
+ import { EnvHttpProxyAgent } from 'undici';
6
+ import { WebSocket } from 'ws';
4
7
  export const STREAMING_POST_TIMEOUT_MS = 30_000;
5
8
  class NodeFetchProvider extends FetchImplementationProvider {
6
9
  getFetch() {
@@ -11,13 +14,27 @@ export class NodeRemote extends AbstractRemote {
11
14
  connector;
12
15
  logger;
13
16
  constructor(connector, logger = DEFAULT_REMOTE_LOGGER, options) {
17
+ // EnvHttpProxyAgent automatically uses relevant env vars for HTTP
18
+ const dispatcher = options?.dispatcher ?? new EnvHttpProxyAgent();
14
19
  super(connector, logger, {
15
- ...(options ?? {}),
16
- fetchImplementation: options?.fetchImplementation ?? new NodeFetchProvider()
20
+ fetchImplementation: options?.fetchImplementation ?? new NodeFetchProvider(),
21
+ fetchOptions: {
22
+ dispatcher
23
+ },
24
+ ...(options ?? {})
17
25
  });
18
26
  this.connector = connector;
19
27
  this.logger = logger;
20
28
  }
29
+ createSocket(url) {
30
+ return new WebSocket(url, {
31
+ // Automatically uses relevant env vars for web sockets
32
+ agent: new Agent.ProxyAgent(),
33
+ headers: {
34
+ 'User-Agent': this.getUserAgent()
35
+ }
36
+ }); // This is compatible in Node environments
37
+ }
21
38
  getUserAgent() {
22
39
  return [
23
40
  super.getUserAgent(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@powersync/node",
3
- "version": "0.2.2",
3
+ "version": "0.4.0",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "public"
@@ -36,14 +36,17 @@
36
36
  },
37
37
  "homepage": "https://docs.powersync.com/",
38
38
  "peerDependencies": {
39
- "@powersync/common": "^1.27.1"
39
+ "@powersync/common": "^1.29.0"
40
40
  },
41
41
  "dependencies": {
42
42
  "@powersync/better-sqlite3": "^0.1.1",
43
43
  "async-lock": "^1.4.0",
44
44
  "bson": "^6.6.0",
45
45
  "comlink": "^4.4.2",
46
- "@powersync/common": "1.27.1"
46
+ "proxy-agent": "^6.5.0",
47
+ "undici": "^7.8.0",
48
+ "ws": "^8.18.1",
49
+ "@powersync/common": "1.29.0"
47
50
  },
48
51
  "devDependencies": {
49
52
  "@types/async-lock": "^1.4.0",