Skip to content
Open
140 changes: 45 additions & 95 deletions .github/workflows/pull-request.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,14 @@ jobs:
strategy:
matrix:
include:
- os: ubuntu-latest
command: make:intel
tag: x64
dist: /apps/desktop/out/make
- os: ubuntu-latest
command: make:arm
tag: arm64
dist: /apps/desktop/out/make
- os: windows-latest
command: make:intel
tag: x64
dist: /apps/desktop/out/make/squirrel.windows/x64/*Setup.exe
- os: macos-13
command: make:intel
tag: x64
dist: /apps/desktop/out/make
- os: macos-13
command: make:arm
tag: arm
dist: /apps/desktop/out/make
- os: macos-13
command: make:universal
tag: universal
dist: /apps/desktop/out/make

- os: macos-13
command: make:arm
tag: arm
dist: /apps/desktop/out/make
- os: windows-latest
command: make:intel
tag: x64
dist: /apps/desktop/out/make/squirrel.windows
runs-on: ${{ matrix.os }}
timeout-minutes: 30
env:
Expand Down Expand Up @@ -100,84 +83,51 @@ jobs:

- name: Upload zip distributives to artifacts
uses: actions/upload-artifact@v4
if: runner.os == 'Windows'
with:
name: Tonkeeper Desktop ${{ runner.os }} x64 archive
name: Tonkeeper-mac-${{ matrix.tag }}-zip
retention-days: 10
path: |
${{ github.workspace }}/apps/desktop/out/make/zip/**/*.zip

- name: Upload distributives to artifacts
- name: Upload mac DMG (optional)
if: runner.os == 'macOS'
uses: actions/upload-artifact@v4
with:
name: Tonkeeper Desktop ${{ runner.os }} ${{ matrix.tag }}
name: Tonkeeper-mac-${{ matrix.tag }}-dmg
retention-days: 10
path: |
${{ github.workspace }}${{ matrix.dist }}

${{ github.workspace }}/apps/desktop/out/make/*.dmg
${{ github.workspace }}/apps/desktop/out/make/**/dmg/**/*.dmg


- name: List Squirrel output
if: runner.os == 'Windows'
shell: pwsh
run: |
Get-ChildItem -Recurse -File apps\desktop\out\make\squirrel.windows |
Select-Object FullName, Length | Format-Table -AutoSize

- name: Upload Windows Squirrel artifacts (RELEASES + full nupkg + delta nupkg)
if: runner.os == 'Windows'
uses: actions/upload-artifact@v4
with:
name: Tonkeeper-win-x64-squirrel
retention-days: 10
if-no-files-found: error
path: |
apps/desktop/out/make/squirrel.windows/**/RELEASES
apps/desktop/out/make/squirrel.windows/**/*-full.nupkg
apps/desktop/out/make/squirrel.windows/**/*-delta.nupkg

- name: Upload Windows Setup (optional)
if: runner.os == 'Windows'
uses: actions/upload-artifact@v4
with:
name: Tonkeeper-win-x64-setup
retention-days: 10
if-no-files-found: error
path: |
apps/desktop/out/make/squirrel.windows/**/*.exe
- name: Clean-up credentials
if: always() && runner.os == 'macOS'
run: |
rm ${{ github.workspace }}/AuthKey.p8

web-build:
uses: ./.github/workflows/web-build.yaml
with:
environment: ${{ github.head_ref }}
secrets: inherit

extension-build:
name: extension-build
runs-on: macos-14
timeout-minutes: 10

steps:
- name: Checkout to git repository
uses: actions/checkout@v4

- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: ${{ env.node-version }}

- name: Enable Corepack
run: |
corepack enable

- name: Yarn cache
uses: actions/cache@v4
with:
path: ./.yarn
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-

- name: Run install
uses: borales/actions-yarn@v5
with:
cmd: install

- name: Run build
uses: borales/actions-yarn@v5
with:
cmd: build:extension

- name: Upload Extension Chrome to artifacts
uses: actions/upload-artifact@v4
with:
name: Extension Chrome
retention-days: 10
path: |
${{ github.workspace }}/apps/extension/dist/chrome

- name: Upload Extension Firefox to artifacts
uses: actions/upload-artifact@v4
with:
name: Extension Firefox
retention-days: 10
path: |
${{ github.workspace }}/apps/extension/dist/firefox

ipad-build:
uses: ./.github/workflows/ipad-build.yaml
secrets: inherit
run: rm -f "$GITHUB_WORKSPACE/AuthKey.p8"
2 changes: 1 addition & 1 deletion apps/desktop/forge.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ const config: ForgeConfig = {
iconUrl: 'https://tonkeeper.com/assets/icon.ico',
setupIcon: path.join(process.cwd(), 'public', 'icon.ico'),
loadingGif: path.join(process.cwd(), 'public', 'install.gif'),
remoteReleases: 'https://github.com/tonkeeper/tonkeeper-web'
noDelta: true
},
['win32']
),
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@tonkeeper/desktop",
"license": "Apache-2.0",
"version": "4.3.0",
"version": "4.3.2",
"description": "Your desktop wallet on The Open Network",
"main": ".webpack/main",
"repository": {
Expand Down
1 change: 1 addition & 0 deletions apps/desktop/src/backgroud.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ interface BackgroundApi {
onTonConnectRequest: (callback: (value: TonConnectAppRequestPayload) => void) => void;
onTonConnectDisconnect: (callback: (value: AccountConnection) => void) => void;
onRefresh: (callback: () => void) => void;
onAutoUpdateAvailable: (callback: (version: string) => void) => void;
}

declare global {
Expand Down
107 changes: 68 additions & 39 deletions apps/desktop/src/electron/autoUpdate.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,80 @@
import { app, autoUpdater, BrowserWindow, webContents } from 'electron';
import { autoUpdater, BrowserWindow } from 'electron';
import log from 'electron-log/main';
import packageJson from '../../package.json';
import { mainStorage } from './storageService';

export default class AppUpdate {
constructor() {
autoUpdater.addListener('update-available', function (event: any) {
console.log('update available');
});
autoUpdater.addListener(
'update-downloaded',
function (event, releaseNotes, releaseName, releaseDate, updateURL) {
notify(
'A new update is ready to install',
`Version ${releaseName} is downloaded and will be automatically installed on Quit`
);
}
);

const appVersion = app.getVersion(); // Get the app version dynamically
const platform = process.platform; // Get the platform dynamically (e.g., 'darwin', 'win32')
const arch = process.arch; // Get the architecture dynamically (e.g., 'arm64', 'x64')

autoUpdater.addListener('error', function (error) {
console.log(error);
});
autoUpdater.addListener('checking-for-update', function (event: any) {
console.log('checking-for-update');
});
export class AutoUpdateManager {
public static versionDownloadedKey = 'versionDownloaded';

private readonly channel = 'stable';

private newAvailableVersion: string | undefined = undefined;

// autoUpdater.addListener('update-not-available', function (event: any) {
// notify('Tonkeeper Pro is up to date', `Version ${releaseName}`);
// });
private win: BrowserWindow;

// private feedBaseUrl = 'https://update.electronjs.org';
private feedBaseUrl = 'https://tonkeeper-web-updater-test.nkuznetsov.workers.dev';

public static async quitAndInstallIfFlagged() {
const flagged = await mainStorage.get(AutoUpdateManager.versionDownloadedKey);
if (flagged) {
return AutoUpdateManager.quitAndInstall();
}
}

public static async quitAndInstall() {
await mainStorage.delete(AutoUpdateManager.versionDownloadedKey);
setImmediate(() => autoUpdater.quitAndInstall());
return true;
}

// // Build the feed URL
// const feedURL = `https://update.electronjs.org/tonkeeper/tonkeeper-web/${platform}-${arch}/${appVersion}`;
constructor(win: BrowserWindow) {
this.win = win;

// autoUpdater.setFeedURL({ url: feedURL });
this.init();
}

check() {
private async init() {
const feedURL = `${this.feedBaseUrl}/${this.getRepoUrl()}/${process.platform}/${
packageJson.version
}/${this.channel}`;
autoUpdater.setFeedURL({ url: feedURL });
this.listenDownload();

const exited = await AutoUpdateManager.quitAndInstallIfFlagged();
if (exited) {
return;
}

autoUpdater.checkForUpdates();
setInterval(() => {
autoUpdater.checkForUpdates();
}, 15 * 60_000);
}

private getRepoUrl(): string {
return packageJson.repository.url
.replace(/^git\+/, '')
.replace(/^https:\/\/github\.com\//, '')
.replace(/\.git$/, '')
.trim();
}
}

function notify(title: string, message: string) {
let windows = BrowserWindow.getAllWindows();
if (windows.length == 0) {
return;
public getNewVersionAvailable() {
return this.newAvailableVersion;
}

// window[0].webContents.send('notify', title, message);
private listenDownload() {
autoUpdater.on('update-downloaded', (_, releaseNotes, releaseName) => {
const version = process.platform === 'win32' ? releaseNotes : releaseName;
this.newAvailableVersion = version;
this.win.webContents.send('app-update::ready', { version });
mainStorage.set(AutoUpdateManager.versionDownloadedKey, version);
log.log('[AutoUpdate] updater new version fetched:', version);
});

autoUpdater.on('error', err => {
log.error('[AutoUpdate] updater error:', err);
});
}
}
11 changes: 10 additions & 1 deletion apps/desktop/src/electron/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { tonConnectSSE } from './sseEvetns';
import { isValidUrlProtocol } from '@tonkeeper/core/dist/utils/common';
import * as electron from 'electron';
import BaseWindow = Electron.BaseWindow;
import { AutoUpdateManager } from './autoUpdate';
import { assertUnreachable } from '@tonkeeper/core/dist/utils/types';

const service = 'tonkeeper.com';

Expand All @@ -15,6 +17,7 @@ const authorizedOpenUrlProtocols = ['http:', 'https:', 'tg:', 'mailto:'];
// eslint-disable-next-line complexity
export const handleBackgroundMessage = async (
window: BaseWindow,
autoUpdateManager: AutoUpdateManager,
message: Message
): Promise<unknown> => {
switch (message.king) {
Expand Down Expand Up @@ -110,7 +113,13 @@ export const handleBackgroundMessage = async (
case 'show-confirm-dialog': {
return electron.dialog.showMessageBoxSync(window, message.options);
}
case 'auto-update-install': {
return autoUpdateManager.quitAndInstall();
}
case 'auto-update-get-has-new-version': {
return autoUpdateManager.getNewVersionAvailable();
}
default:
throw new Error(`Unknown message: ${JSON.stringify(message)}`);
assertUnreachable(message);
}
};
8 changes: 5 additions & 3 deletions apps/desktop/src/electron/mainWindow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { handleBackgroundMessage } from '../electron/background';
import { Message } from '../libs/message';
import { createAppMenu } from './menu';
import { cookieJar } from './cookie';
import AppUpdate from './autoUpdate';
import { AutoUpdateManager } from './autoUpdate';

// This allows TypeScript to pick up the magic constants that's auto-generated by Forge's Webpack
// plugin that tells the Electron app where to look for the Webpack-bundled app code (depending on
Expand Down Expand Up @@ -50,9 +50,11 @@ export abstract class MainWindow {
resizable: true
});

const menu = Menu.buildFromTemplate(createAppMenu(new AppUpdate()));
const menu = Menu.buildFromTemplate(createAppMenu());
Menu.setApplicationMenu(menu);

const updater = new AutoUpdateManager(this.mainWindow);

// and load the index.html of the app.
this.mainWindow.loadURL(MAIN_WINDOW_WEBPACK_ENTRY);

Expand All @@ -68,7 +70,7 @@ export abstract class MainWindow {

ipcMain.handle('message', async (event, message: Message) => {
try {
return await handleBackgroundMessage(this.mainWindow, message);
return await handleBackgroundMessage(this.mainWindow, updater, message);
} catch (e) {
return e;
}
Expand Down
Loading