Skip to content

Commit fbb111e

Browse files
Cleanup asset download name mapping. Update demos.
1 parent f937963 commit fbb111e

File tree

5 files changed

+71
-96
lines changed

5 files changed

+71
-96
lines changed

demos/example-electron-node/README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ In particular:
99
queries. This worker is part of the `@powersync/node` package and wouldn't be copied into the resulting Electron
1010
app by default. For this reason, this example has its own `src/main/worker.ts` loaded with `new URL('./worker.ts', import.meta.url)`.
1111
2. In addition to the worker, PowerSync requires access to a SQLite extension providing sync functionality.
12-
This file is also part of the `@powersync/node` package and called `powersync.dll`, `libpowersync.dylib` or
13-
`libpowersync.so` depending on the operating system.
12+
This file is also part of the `@powersync/node` package and is the prebuilt release asset (for example
13+
`powersync_x64.dll`, `libpowersync_x64.dylib` or `libpowersync_x64.so`) depending on the operating system and
14+
architecture.
1415
We use the `copy-webpack-plugin` package to make sure a copy of that file is available to the main process,
1516
and load it in the custom `src/main/worker.ts`.
1617
3. The `get()` and `getAll()` methods are exposed to the renderer process with an IPC channel.
@@ -21,7 +22,7 @@ To see it in action:
2122
2. Copy `.env.local.template` to `.env.local`, and complete the environment variables. You can generate a [temporary development token](https://docs.powersync.com/usage/installation/authentication-setup/development-tokens), or leave blank to test with local-only data.
2223
The example works with the schema from the [PowerSync + Supabase tutorial](https://docs.powersync.com/integration-guides/supabase-+-powersync#supabase-powersync).
2324
3. `cd` into this directory. In this mono-repo, you'll have to run `./node_modules/.bin/electron-rebuild` once to make sure `@powersync/better-sqlite3` was compiled with Electron's toolchain.
24-
3. Finally, run `pnpm start`.
25+
4. Finally, run `pnpm start`.
2526

2627
Apart from the build setup, this example is purposefully kept simple.
2728
To make sure PowerSync is working, you can run `await powersync.get('SELECT powersync_rs_version()');` in the DevTools

demos/example-electron-node/config.ts

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
1-
import OS from 'node:os';
21
import path from 'node:path';
32

4-
import type { ForgeConfig } from '@electron-forge/shared-types';
5-
import { MakerSquirrel } from '@electron-forge/maker-squirrel';
6-
import { MakerZIP } from '@electron-forge/maker-zip';
73
import { MakerDeb } from '@electron-forge/maker-deb';
84
import { MakerRpm } from '@electron-forge/maker-rpm';
5+
import { MakerSquirrel } from '@electron-forge/maker-squirrel';
6+
import { MakerZIP } from '@electron-forge/maker-zip';
97
import { AutoUnpackNativesPlugin } from '@electron-forge/plugin-auto-unpack-natives';
108
import { WebpackPlugin } from '@electron-forge/plugin-webpack';
11-
import { type Configuration, type ModuleOptions, type DefinePlugin } from 'webpack';
9+
import type { ForgeConfig } from '@electron-forge/shared-types';
10+
import { getPowerSyncExtensionFilename } from '@powersync/node/worker.js';
11+
import type ICopyPlugin from 'copy-webpack-plugin';
1212
import * as dotenv from 'dotenv';
1313
import type IForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
14-
import type ICopyPlugin from 'copy-webpack-plugin';
15-
14+
import { type Configuration, type DefinePlugin, type ModuleOptions } from 'webpack';
1615
dotenv.config({ path: '.env.local' });
1716

1817
const ForkTsCheckerWebpackPlugin: typeof IForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
@@ -57,17 +56,7 @@ const defaultWebpackRules: () => Required<ModuleOptions>['rules'] = () => {
5756
];
5857
};
5958

60-
const platform = OS.platform();
61-
let extensionPath: string;
62-
if (platform === 'win32') {
63-
extensionPath = 'powersync.dll';
64-
} else if (platform === 'linux') {
65-
extensionPath = 'libpowersync.so';
66-
} else if (platform === 'darwin') {
67-
extensionPath = 'libpowersync.dylib';
68-
} else {
69-
throw 'Unknown platform, PowerSync for Node.js currently supports Windows, Linux and macOS.';
70-
}
59+
let extensionFilename = getPowerSyncExtensionFilename();
7160

7261
const mainConfig: Configuration = {
7362
/**
@@ -84,8 +73,8 @@ const mainConfig: Configuration = {
8473
new CopyPlugin({
8574
patterns: [
8675
{
87-
from: path.resolve(require.resolve('@powersync/node/package.json'), `../lib/${extensionPath}`),
88-
to: path.join('powersync', extensionPath)
76+
from: path.resolve(require.resolve('@powersync/node/package.json'), `../lib/${extensionFilename}`),
77+
to: path.join('powersync', extensionFilename)
8978
}
9079
]
9180
}),

demos/example-electron-node/src/main/worker.ts

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,14 @@
1-
import * as path from 'node:path';
2-
import OS from 'node:os';
31
import Database from 'better-sqlite3';
2+
import * as path from 'node:path';
43

5-
import { startPowerSyncWorker } from '@powersync/node/worker.js';
4+
import { getPowerSyncExtensionFilename, startPowerSyncWorker } from '@powersync/node/worker.js';
65

76
function resolvePowerSyncCoreExtension() {
8-
const platform = OS.platform();
9-
let extensionPath: string;
10-
if (platform === 'win32') {
11-
extensionPath = 'powersync.dll';
12-
} else if (platform === 'linux') {
13-
extensionPath = 'libpowersync.so';
14-
} else if (platform === 'darwin') {
15-
extensionPath = 'libpowersync.dylib';
16-
} else {
17-
throw 'Unknown platform, PowerSync for Node.js currently supports Windows, Linux and macOS.';
18-
}
7+
const extensionFilename = getPowerSyncExtensionFilename();
198

209
// This example uses copy-webpack-plugin to copy the prebuilt library over. This ensures that it is
2110
// available in packaged release builds.
22-
let libraryPath = path.resolve(__dirname, 'powersync', extensionPath);
11+
let libraryPath = path.resolve(__dirname, 'powersync', extensionFilename);
2312

2413
if (__dirname.indexOf('app.asar') != -1) {
2514
// Our build configuration ensures the extension is always available outside of the archive too.

packages/node/download_core.js

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,7 @@ const versionHashes = {
1414
'libpowersync_aarch64.dylib': 'bfb4f1ec207b298aff560f1825f8123d24316edaa27b6df3a17dd49466576b92'
1515
};
1616

17-
// Map of all assets to their destinations
18-
const assetMap = {
19-
'powersync_x64.dll': 'powersync.dll',
20-
'libpowersync_x64.so': 'libpowersync.so',
21-
'libpowersync_aarch64.so': 'libpowersync-aarch64.so',
22-
'libpowersync_x64.dylib': 'libpowersync.dylib',
23-
'libpowersync_aarch64.dylib': 'libpowersync-aarch64.dylib'
24-
};
17+
const assets = Object.keys(versionHashes);
2518

2619
const hashStream = async (input) => {
2720
for await (const chunk of input.pipe(createHash('sha256')).setEncoding('hex')) {
@@ -42,14 +35,14 @@ const hashLocal = async (filePath) => {
4235
}
4336
};
4437

45-
const downloadAsset = async (asset, destination) => {
46-
const destinationPath = path.resolve('lib', destination);
38+
const downloadAsset = async (asset) => {
39+
const destinationPath = path.resolve('lib', asset);
4740
const expectedHash = versionHashes[asset];
4841

4942
// Check if file exists and has correct hash
5043
const currentHash = await hashLocal(destinationPath);
5144
if (currentHash == expectedHash) {
52-
console.debug(`${destination} is up-to-date, skipping download`);
45+
console.debug(`${asset} is up-to-date, skipping download`);
5346
return;
5447
}
5548

@@ -68,17 +61,16 @@ const downloadAsset = async (asset, destination) => {
6861
if (hashAfterDownloading != expectedHash) {
6962
throw `Unexpected hash after downloading ${asset} (got ${hashAfterDownloading}, expected ${expectedHash})`;
7063
}
71-
console.log(`Successfully downloaded ${destination}`);
64+
console.log(`Successfully downloaded ${asset}`);
7265
};
7366

74-
const checkAsset = async (asset, destination) => {
75-
const destinationPath = path.resolve('lib', destination);
67+
const checkAsset = async (asset) => {
68+
const destinationPath = path.resolve('lib', asset);
7669
const expectedHash = versionHashes[asset];
7770
const currentHash = await hashLocal(destinationPath);
7871

7972
return {
8073
asset,
81-
destination,
8274
destinationPath,
8375
expectedHash,
8476
currentHash,
@@ -96,9 +88,7 @@ const download = async () => {
9688

9789
// First check all assets
9890
console.log('Checking existing files...');
99-
const checks = await Promise.all(
100-
Object.entries(assetMap).map(([asset, destination]) => checkAsset(asset, destination))
101-
);
91+
const checks = await Promise.all(assets.map((asset) => checkAsset(asset, asset)));
10292

10393
const toDownload = checks.filter((check) => !check.isValid);
10494
const upToDate = checks.filter((check) => check.isValid);
@@ -107,23 +97,22 @@ const download = async () => {
10797
if (upToDate.length > 0) {
10898
console.log('\nUp-to-date files:');
10999
for (const check of upToDate) {
110-
console.log(` ✓ ${check.destination}`);
100+
console.log(` ✓ ${check.asset}`);
111101
}
112102
}
113103

114104
if (toDownload.length > 0) {
115105
console.log('\nFiles to download:');
116106
for (const check of toDownload) {
117107
if (!check.exists) {
118-
console.log(` • ${check.destination} (missing)`);
108+
console.log(` • ${check.asset} (missing)`);
119109
} else {
120-
console.log(` • ${check.destination} (hash mismatch)`);
110+
console.log(` • ${check.asset} (hash mismatch)`);
121111
}
122112
}
123113

124114
console.log('\nStarting downloads...');
125-
// Download required assets in parallel
126-
await Promise.all(toDownload.map((check) => downloadAsset(check.asset, check.destination)));
115+
await Promise.all(toDownload.map((check) => downloadAsset(check.asset)));
127116

128117
console.log('\nAll downloads completed successfully!');
129118
} else {

packages/node/src/db/SqliteWorker.ts

Lines changed: 42 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -22,48 +22,55 @@ export interface PowerSyncWorkerOptions {
2222
loadBetterSqlite3: () => Promise<any>;
2323
}
2424

25+
/**
26+
* @returns The relevant PowerSync extension binary filename for the current platform and architecture
27+
*/
28+
export function getPowerSyncExtensionFilename() {
29+
const platform = OS.platform();
30+
const arch = OS.arch();
31+
let extensionFile: string;
32+
33+
if (platform == 'win32') {
34+
if (arch == 'x64') {
35+
extensionFile = 'powersync_x64.dll';
36+
} else {
37+
throw new Error('Windows platform only supports x64 architecture.');
38+
}
39+
} else if (platform == 'linux') {
40+
if (arch == 'x64') {
41+
extensionFile = 'libpowersync_x64.so';
42+
} else if (arch == 'arm64') {
43+
extensionFile = 'libpowersync_aarch64.so';
44+
} else {
45+
throw new Error('Linux platform only supports x64 and arm64 architectures.');
46+
}
47+
} else if (platform == 'darwin') {
48+
if (arch == 'x64') {
49+
extensionFile = 'libpowersync_x64.dylib';
50+
} else if (arch == 'arm64') {
51+
extensionFile = 'libpowersync_aarch64.dylib';
52+
} else {
53+
throw new Error('macOS platform only supports x64 and arm64 architectures.');
54+
}
55+
} else {
56+
throw new Error(
57+
`Unknown platform: ${platform}, PowerSync for Node.js currently supports Windows, Linux and macOS.`
58+
);
59+
}
60+
61+
return extensionFile;
62+
}
63+
2564
export function startPowerSyncWorker(options?: Partial<PowerSyncWorkerOptions>) {
2665
const resolvedOptions: PowerSyncWorkerOptions = {
2766
extensionPath() {
2867
const isCommonJsModule = isBundledToCommonJs;
29-
30-
const platform = OS.platform();
31-
const arch = OS.arch();
32-
let extensionPath: string;
33-
34-
if (platform == 'win32') {
35-
if (arch == 'x64') {
36-
extensionPath = 'powersync.dll';
37-
} else {
38-
throw new Error('Windows platform only supports x64 architecture.');
39-
}
40-
} else if (platform == 'linux') {
41-
if (arch == 'x64') {
42-
extensionPath = 'libpowersync.so';
43-
} else if (arch == 'arm64') {
44-
extensionPath = 'libpowersync-aarch64.so';
45-
} else {
46-
throw new Error('Linux platform only supports x64 and arm64 architectures.');
47-
}
48-
} else if (platform == 'darwin') {
49-
if (arch == 'x64') {
50-
extensionPath = 'libpowersync.dylib';
51-
} else if (arch == 'arm64') {
52-
extensionPath = 'libpowersync-aarch64.dylib';
53-
} else {
54-
throw new Error('macOS platform only supports x64 and arm64 architectures.');
55-
}
56-
} else {
57-
throw new Error(
58-
`Unknown platform: ${platform}, PowerSync for Node.js currently supports Windows, Linux and macOS.`
59-
);
60-
}
61-
68+
const extensionFilename = getPowerSyncExtensionFilename();
6269
let resolved: string;
6370
if (isCommonJsModule) {
64-
resolved = path.resolve(__dirname, '../lib/', extensionPath);
71+
resolved = path.resolve(__dirname, '../lib/', extensionFilename);
6572
} else {
66-
resolved = url.fileURLToPath(new URL(`../${extensionPath}`, import.meta.url));
73+
resolved = url.fileURLToPath(new URL(`../${extensionFilename}`, import.meta.url));
6774
}
6875

6976
return resolved;

0 commit comments

Comments
 (0)