1- // TODO: Make this a pre-publish hook and just bundle everything
21import { createHash } from 'node:crypto' ;
3- import * as OS from 'node:os' ;
42import * as fs from 'node:fs/promises' ;
53import * as path from 'node:path' ;
64import { Readable } from 'node:stream' ;
75import { finished } from 'node:stream/promises' ;
8- import { exit } from 'node:process' ;
96
107// When changing this version, run node download_core.js update_hashes
118const version = '0.4.6' ;
@@ -17,33 +14,24 @@ const versionHashes = {
1714 'libpowersync_aarch64.dylib' : 'bfb4f1ec207b298aff560f1825f8123d24316edaa27b6df3a17dd49466576b92'
1815} ;
1916
20- const platform = OS . platform ( ) ;
21- let destination ;
22- let asset ;
23-
24- if ( platform === 'win32' ) {
25- asset = 'powersync_x64.dll' ;
26- destination = 'powersync.dll' ;
27- } else if ( platform === 'linux' ) {
28- asset = OS . arch ( ) === 'x64' ? 'libpowersync_x64.so' : 'libpowersync_aarch64.so' ;
29- destination = 'libpowersync.so' ;
30- } else if ( platform === 'darwin' ) {
31- asset = OS . arch ( ) === 'x64' ? 'libpowersync_x64.dylib' : 'libpowersync_aarch64.dylib' ;
32- destination = 'libpowersync.dylib' ;
33- }
34-
35- const expectedHash = versionHashes [ asset ] ;
36- const destinationPath = path . resolve ( 'lib' , destination ) ;
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+ } ;
3725
3826const hashStream = async ( input ) => {
3927 for await ( const chunk of input . pipe ( createHash ( 'sha256' ) ) . setEncoding ( 'hex' ) ) {
4028 return chunk ;
4129 }
4230} ;
4331
44- const hashLocal = async ( ) => {
32+ const hashLocal = async ( filePath ) => {
4533 try {
46- const handle = await fs . open ( destinationPath , 'r' ) ;
34+ const handle = await fs . open ( filePath , 'r' ) ;
4735 const input = handle . createReadStream ( ) ;
4836
4937 const result = await hashStream ( input ) ;
@@ -54,31 +42,92 @@ const hashLocal = async () => {
5442 }
5543} ;
5644
57- const download = async ( ) => {
58- if ( ( await hashLocal ( ) ) == expectedHash ) {
59- console . debug ( 'Local copy is up-to-date, skipping download' ) ;
60- exit ( 0 ) ;
45+ const downloadAsset = async ( asset , destination ) => {
46+ const destinationPath = path . resolve ( 'lib' , destination ) ;
47+ const expectedHash = versionHashes [ asset ] ;
48+
49+ // Check if file exists and has correct hash
50+ const currentHash = await hashLocal ( destinationPath ) ;
51+ if ( currentHash === expectedHash ) {
52+ console . debug ( `${ destination } is up-to-date, skipping download` ) ;
53+ return ;
6154 }
6255
6356 const url = `https://github.com/powersync-ja/powersync-sqlite-core/releases/download/v${ version } /${ asset } ` ;
57+ console . log ( `Downloading ${ url } ` ) ;
6458 const response = await fetch ( url ) ;
6559 if ( response . status != 200 ) {
6660 throw `Could not download ${ url } ` ;
6761 }
6862
63+ const file = await fs . open ( destinationPath , 'w' ) ;
64+ await finished ( Readable . fromWeb ( response . body ) . pipe ( file . createWriteStream ( ) ) ) ;
65+ await file . close ( ) ;
66+
67+ const hashAfterDownloading = await hashLocal ( destinationPath ) ;
68+ if ( hashAfterDownloading != expectedHash ) {
69+ throw `Unexpected hash after downloading ${ asset } (got ${ hashAfterDownloading } , expected ${ expectedHash } )` ;
70+ }
71+ console . log ( `Successfully downloaded ${ destination } ` ) ;
72+ } ;
73+
74+ const checkAsset = async ( asset , destination ) => {
75+ const destinationPath = path . resolve ( 'lib' , destination ) ;
76+ const expectedHash = versionHashes [ asset ] ;
77+ const currentHash = await hashLocal ( destinationPath ) ;
78+
79+ return {
80+ asset,
81+ destination,
82+ destinationPath,
83+ expectedHash,
84+ currentHash,
85+ exists : currentHash !== null ,
86+ isValid : currentHash === expectedHash
87+ } ;
88+ } ;
89+
90+ const download = async ( ) => {
6991 try {
7092 await fs . access ( 'lib' ) ;
7193 } catch {
7294 await fs . mkdir ( 'lib' ) ;
7395 }
7496
75- const file = await fs . open ( destinationPath , 'w' ) ;
76- await finished ( Readable . fromWeb ( response . body ) . pipe ( file . createWriteStream ( ) ) ) ;
77- await file . close ( ) ;
97+ // First check all assets
98+ console . log ( 'Checking existing files...' ) ;
99+ const checks = await Promise . all (
100+ Object . entries ( assetMap ) . map ( ( [ asset , destination ] ) => checkAsset ( asset , destination ) )
101+ ) ;
78102
79- const hashAfterDownloading = await hashLocal ( ) ;
80- if ( hashAfterDownloading != expectedHash ) {
81- throw `Unexpected hash after downloading (got ${ hashAfterDownloading } , expected ${ expectedHash } )` ;
103+ const toDownload = checks . filter ( ( check ) => ! check . isValid ) ;
104+ const upToDate = checks . filter ( ( check ) => check . isValid ) ;
105+
106+ // Print summary
107+ if ( upToDate . length > 0 ) {
108+ console . log ( '\nUp-to-date files:' ) ;
109+ for ( const check of upToDate ) {
110+ console . log ( ` ✓ ${ check . destination } ` ) ;
111+ }
112+ }
113+
114+ if ( toDownload . length > 0 ) {
115+ console . log ( '\nFiles to download:' ) ;
116+ for ( const check of toDownload ) {
117+ if ( ! check . exists ) {
118+ console . log ( ` • ${ check . destination } (missing)` ) ;
119+ } else {
120+ console . log ( ` • ${ check . destination } (hash mismatch)` ) ;
121+ }
122+ }
123+
124+ console . log ( '\nStarting downloads...' ) ;
125+ // Download required assets in parallel
126+ await Promise . all ( toDownload . map ( ( check ) => downloadAsset ( check . asset , check . destination ) ) ) ;
127+
128+ console . log ( '\nAll downloads completed successfully!' ) ;
129+ } else {
130+ console . log ( '\nAll files are up-to-date, nothing to download.' ) ;
82131 }
83132} ;
84133
0 commit comments