Compare commits
24 changed files with 68 additions and 303 deletions
|
|
@ -1,56 +0,0 @@
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
|
||||||
- cron: "30 3 * * *"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
cleanup-workflow-runs:
|
|
||||||
runs-on: docker
|
|
||||||
steps:
|
|
||||||
- name: Install Packages
|
|
||||||
run: apt-get update && apt-get install -y curl jq
|
|
||||||
|
|
||||||
- name: Delete workflow runs older than 14 days
|
|
||||||
env:
|
|
||||||
TOKEN: ${{ forgejo.token }}
|
|
||||||
API: ${{ forgejo.api_url }}
|
|
||||||
REPO: ${{ forgejo.repository }}
|
|
||||||
CURRENT_RUN_ID: ${{ forgejo.run_id }}
|
|
||||||
run: |
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
CUTOFF="$(date -u -d "14 days ago" +"%Y-%m-%dT%H:%M:%SZ")"
|
|
||||||
PAGE=1
|
|
||||||
DELETE_IDS=delete-workflow-runs.txt
|
|
||||||
|
|
||||||
: > "$DELETE_IDS"
|
|
||||||
|
|
||||||
while :; do
|
|
||||||
curl -fsS \
|
|
||||||
-H "Authorization: token $TOKEN" \
|
|
||||||
"$API/repos/$REPO/actions/runs?page=$PAGE&limit=50" \
|
|
||||||
-o runs.json
|
|
||||||
|
|
||||||
COUNT="$(jq '.workflow_runs | length' runs.json)"
|
|
||||||
test "$COUNT" -gt 0 || break
|
|
||||||
|
|
||||||
jq -r \
|
|
||||||
--arg cutoff "$CUTOFF" \
|
|
||||||
--arg current "$CURRENT_RUN_ID" \
|
|
||||||
'.workflow_runs[]
|
|
||||||
| select((.id | tostring) != $current)
|
|
||||||
| select(["success", "failure", "cancelled", "skipped", "succeeded", "failed"] | index(.status))
|
|
||||||
| select(.created < $cutoff)
|
|
||||||
| .id' runs.json \
|
|
||||||
>> "$DELETE_IDS"
|
|
||||||
|
|
||||||
PAGE="$((PAGE + 1))"
|
|
||||||
done
|
|
||||||
|
|
||||||
while IFS= read -r run_id; do
|
|
||||||
test -n "$run_id" || continue
|
|
||||||
echo "Deleting workflow run $run_id"
|
|
||||||
curl -fsS -X DELETE \
|
|
||||||
-H "Authorization: token $TOKEN" \
|
|
||||||
"$API/repos/$REPO/actions/runs/$run_id"
|
|
||||||
done < "$DELETE_IDS"
|
|
||||||
|
|
@ -232,46 +232,6 @@ jobs:
|
||||||
-F "attachment=@$file"
|
-F "attachment=@$file"
|
||||||
done
|
done
|
||||||
|
|
||||||
- name: Delete dev releases for prod version
|
|
||||||
env:
|
|
||||||
TOKEN: ${{ forgejo.token }}
|
|
||||||
API: ${{ forgejo.api_url }}
|
|
||||||
REPO: ${{ forgejo.repository }}
|
|
||||||
TAG: ${{ steps.version.outputs.tag }}
|
|
||||||
run: |
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
PAGE=1
|
|
||||||
PREFIX="$TAG-dev-"
|
|
||||||
DELETE_RELEASES=delete-dev-releases.tsv
|
|
||||||
|
|
||||||
: > "$DELETE_RELEASES"
|
|
||||||
|
|
||||||
while :; do
|
|
||||||
curl -fsS \
|
|
||||||
-H "Authorization: token $TOKEN" \
|
|
||||||
"$API/repos/$REPO/releases?page=$PAGE&limit=50&pre-release=true" \
|
|
||||||
-o releases.json
|
|
||||||
|
|
||||||
COUNT="$(jq 'length' releases.json)"
|
|
||||||
test "$COUNT" -gt 0 || break
|
|
||||||
|
|
||||||
jq -r \
|
|
||||||
--arg prefix "$PREFIX" \
|
|
||||||
'.[] | select(.prerelease == true) | select(.tag_name | startswith($prefix)) | [.id, .tag_name] | @tsv' releases.json \
|
|
||||||
>> "$DELETE_RELEASES"
|
|
||||||
|
|
||||||
PAGE="$((PAGE + 1))"
|
|
||||||
done
|
|
||||||
|
|
||||||
while IFS="$(printf '\t')" read -r release_id release_tag; do
|
|
||||||
test -n "$release_id" || continue
|
|
||||||
echo "Deleting dev release $release_tag"
|
|
||||||
curl -fsS -X DELETE \
|
|
||||||
-H "Authorization: token $TOKEN" \
|
|
||||||
"$API/repos/$REPO/releases/$release_id"
|
|
||||||
done < "$DELETE_RELEASES"
|
|
||||||
|
|
||||||
- name: Update root flake release hash
|
- name: Update root flake release hash
|
||||||
env:
|
env:
|
||||||
TAG: ${{ steps.version.outputs.tag }}
|
TAG: ${{ steps.version.outputs.tag }}
|
||||||
|
|
|
||||||
|
|
@ -5,5 +5,4 @@ coverage
|
||||||
*.tsbuildinfo
|
*.tsbuildinfo
|
||||||
bun.lock
|
bun.lock
|
||||||
apps/tauri/src-tauri
|
apps/tauri/src-tauri
|
||||||
apps/electron/release
|
|
||||||
licenses
|
licenses
|
||||||
|
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 13 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.2 KiB |
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 34 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 38 KiB |
|
|
@ -41,7 +41,6 @@
|
||||||
"productName": "Tensamin",
|
"productName": "Tensamin",
|
||||||
"executableName": "tensamin",
|
"executableName": "tensamin",
|
||||||
"artifactName": "Tensamin-${version}-${os}-${arch}.${ext}",
|
"artifactName": "Tensamin-${version}-${os}-${arch}.${ext}",
|
||||||
"icon": "build/icons/icon.png",
|
|
||||||
"directories": {
|
"directories": {
|
||||||
"output": "release"
|
"output": "release"
|
||||||
},
|
},
|
||||||
|
|
@ -53,19 +52,10 @@
|
||||||
{
|
{
|
||||||
"from": "../web/dist",
|
"from": "../web/dist",
|
||||||
"to": "web"
|
"to": "web"
|
||||||
},
|
|
||||||
{
|
|
||||||
"from": "build/icons/icon.png",
|
|
||||||
"to": "icons/icon.png"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"linux": {
|
"linux": {
|
||||||
"target": [
|
"target": ["AppImage", "deb", "rpm"],
|
||||||
"AppImage",
|
|
||||||
"deb",
|
|
||||||
"rpm"
|
|
||||||
],
|
|
||||||
"icon": "build/icons",
|
|
||||||
"executableName": "tensamin",
|
"executableName": "tensamin",
|
||||||
"category": "Network",
|
"category": "Network",
|
||||||
"maintainer": "Methanium",
|
"maintainer": "Methanium",
|
||||||
|
|
@ -77,17 +67,10 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"win": {
|
"win": {
|
||||||
"target": [
|
"target": ["nsis", "portable"]
|
||||||
"nsis",
|
|
||||||
"portable"
|
|
||||||
],
|
|
||||||
"icon": "build/icons/icon.ico"
|
|
||||||
},
|
},
|
||||||
"mac": {
|
"mac": {
|
||||||
"target": [
|
"target": ["dmg"]
|
||||||
"dmg"
|
|
||||||
],
|
|
||||||
"icon": "build/icons/icon.icns"
|
|
||||||
},
|
},
|
||||||
"publish": null
|
"publish": null
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,5 @@
|
||||||
import { createHash } from "node:crypto";
|
import { createHash } from "node:crypto";
|
||||||
import {
|
import { createReadStream, existsSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
||||||
createReadStream,
|
|
||||||
existsSync,
|
|
||||||
readdirSync,
|
|
||||||
statSync,
|
|
||||||
writeFileSync,
|
|
||||||
} from "node:fs";
|
|
||||||
import { basename, join } from "node:path";
|
import { basename, join } from "node:path";
|
||||||
import rootPackage from "../../../package.json" with { type: "json" };
|
import rootPackage from "../../../package.json" with { type: "json" };
|
||||||
|
|
||||||
|
|
@ -61,10 +55,7 @@ const metadata = {
|
||||||
artifacts,
|
artifacts,
|
||||||
};
|
};
|
||||||
|
|
||||||
writeFileSync(
|
writeFileSync(join(outDir, "electron-release-metadata.json"), `${JSON.stringify(metadata, null, 2)}\n`);
|
||||||
join(outDir, "electron-release-metadata.json"),
|
|
||||||
`${JSON.stringify(metadata, null, 2)}\n`,
|
|
||||||
);
|
|
||||||
writeFileSync(
|
writeFileSync(
|
||||||
join(outDir, "SHA256SUMS"),
|
join(outDir, "SHA256SUMS"),
|
||||||
`${artifacts.map((artifact) => `${artifact.sha256} ${artifact.name}`).join("\n")}\n`,
|
`${artifacts.map((artifact) => `${artifact.sha256} ${artifact.name}`).join("\n")}\n`,
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,9 @@
|
||||||
import { execFile } from "node:child_process";
|
import { execFile } from "node:child_process";
|
||||||
import { fileURLToPath } from "node:url";
|
import { fileURLToPath } from "node:url";
|
||||||
import { dirname, join, resolve } from "node:path";
|
import { dirname, join, resolve } from "node:path";
|
||||||
import {
|
import { app, BrowserWindow, desktopCapturer, ipcMain, session, shell } from "electron";
|
||||||
app,
|
|
||||||
BrowserWindow,
|
|
||||||
desktopCapturer,
|
|
||||||
ipcMain,
|
|
||||||
session,
|
|
||||||
shell,
|
|
||||||
} from "electron";
|
|
||||||
import { checkForUpdates } from "./updates.js";
|
import { checkForUpdates } from "./updates.js";
|
||||||
import {
|
import { ipcChannels, type DesktopScreenShareCapabilities } from "../shared/ipc.js";
|
||||||
ipcChannels,
|
|
||||||
type DesktopScreenShareCapabilities,
|
|
||||||
} from "../shared/ipc.js";
|
|
||||||
|
|
||||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
const verbose = process.argv.includes("--verbose");
|
const verbose = process.argv.includes("--verbose");
|
||||||
|
|
@ -26,11 +16,7 @@ if (verbose) {
|
||||||
app.commandLine.appendSwitch("log-level", "0");
|
app.commandLine.appendSwitch("log-level", "0");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (process.platform === "linux" && process.env.XDG_SESSION_TYPE === "wayland" && !process.env.TENSAMIN_ENABLE_VULKAN) {
|
||||||
process.platform === "linux" &&
|
|
||||||
process.env.XDG_SESSION_TYPE === "wayland" &&
|
|
||||||
!process.env.TENSAMIN_ENABLE_VULKAN
|
|
||||||
) {
|
|
||||||
app.commandLine.appendSwitch("disable-features", "Vulkan");
|
app.commandLine.appendSwitch("disable-features", "Vulkan");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,12 +34,6 @@ function getRendererIndex() {
|
||||||
return join(process.resourcesPath, "web", "index.html");
|
return join(process.resourcesPath, "web", "index.html");
|
||||||
}
|
}
|
||||||
|
|
||||||
function getWindowIcon() {
|
|
||||||
if (process.platform === "darwin") return undefined;
|
|
||||||
if (app.isPackaged) return join(process.resourcesPath, "icons", "icon.png");
|
|
||||||
return resolve(__dirname, "../../build/icons/icon.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPlatform(): DesktopScreenShareCapabilities["platform"] {
|
function getPlatform(): DesktopScreenShareCapabilities["platform"] {
|
||||||
if (process.platform === "linux") return "linux";
|
if (process.platform === "linux") return "linux";
|
||||||
if (process.platform === "darwin") return "macos";
|
if (process.platform === "darwin") return "macos";
|
||||||
|
|
@ -101,8 +81,7 @@ async function listAudioOutputs() {
|
||||||
if (!sink || typeof sink !== "object") return null;
|
if (!sink || typeof sink !== "object") return null;
|
||||||
const record = sink as Record<string, unknown>;
|
const record = sink as Record<string, unknown>;
|
||||||
const id = record.index == null ? undefined : String(record.index);
|
const id = record.index == null ? undefined : String(record.index);
|
||||||
const name =
|
const name = typeof record.description === "string" ? record.description : id;
|
||||||
typeof record.description === "string" ? record.description : id;
|
|
||||||
if (!id || !name) return null;
|
if (!id || !name) return null;
|
||||||
return { id, name, isDefault: false };
|
return { id, name, isDefault: false };
|
||||||
})
|
})
|
||||||
|
|
@ -128,8 +107,7 @@ async function listScreenShareSources() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function registerDisplayMediaHandler() {
|
function registerDisplayMediaHandler() {
|
||||||
session.defaultSession.setDisplayMediaRequestHandler(
|
session.defaultSession.setDisplayMediaRequestHandler(async (_request, callback) => {
|
||||||
async (_request, callback) => {
|
|
||||||
verboseLog("display media request", { selectedScreenShareSourceId });
|
verboseLog("display media request", { selectedScreenShareSourceId });
|
||||||
|
|
||||||
const sources = await desktopCapturer.getSources({
|
const sources = await desktopCapturer.getSources({
|
||||||
|
|
@ -137,9 +115,7 @@ function registerDisplayMediaHandler() {
|
||||||
thumbnailSize: { width: 0, height: 0 },
|
thumbnailSize: { width: 0, height: 0 },
|
||||||
});
|
});
|
||||||
|
|
||||||
const selected = sources.find(
|
const selected = sources.find((source) => source.id === selectedScreenShareSourceId);
|
||||||
(source) => source.id === selectedScreenShareSourceId,
|
|
||||||
);
|
|
||||||
selectedScreenShareSourceId = null;
|
selectedScreenShareSourceId = null;
|
||||||
const video = selected ?? sources[0];
|
const video = selected ?? sources[0];
|
||||||
|
|
||||||
|
|
@ -154,8 +130,7 @@ function registerDisplayMediaHandler() {
|
||||||
}
|
}
|
||||||
|
|
||||||
callback({ video });
|
callback({ video });
|
||||||
},
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function registerIpc() {
|
function registerIpc() {
|
||||||
|
|
@ -163,26 +138,16 @@ function registerIpc() {
|
||||||
|
|
||||||
ipcMain.handle(ipcChannels.listScreenShareSources, listScreenShareSources);
|
ipcMain.handle(ipcChannels.listScreenShareSources, listScreenShareSources);
|
||||||
ipcMain.handle(ipcChannels.listScreenShareAudioOutputs, listAudioOutputs);
|
ipcMain.handle(ipcChannels.listScreenShareAudioOutputs, listAudioOutputs);
|
||||||
ipcMain.handle(
|
ipcMain.handle(ipcChannels.getScreenShareCapabilities, getScreenShareCapabilities);
|
||||||
ipcChannels.getScreenShareCapabilities,
|
ipcMain.handle(ipcChannels.selectScreenShareSource, (_event, sourceId: unknown) => {
|
||||||
getScreenShareCapabilities,
|
if (typeof sourceId !== "string" || sourceId.length === 0 || sourceId.length > 256) {
|
||||||
);
|
|
||||||
ipcMain.handle(
|
|
||||||
ipcChannels.selectScreenShareSource,
|
|
||||||
(_event, sourceId: unknown) => {
|
|
||||||
if (
|
|
||||||
typeof sourceId !== "string" ||
|
|
||||||
sourceId.length === 0 ||
|
|
||||||
sourceId.length > 256
|
|
||||||
) {
|
|
||||||
throw new Error("Invalid screen share source id.");
|
throw new Error("Invalid screen share source id.");
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedScreenShareSourceId = sourceId;
|
selectedScreenShareSourceId = sourceId;
|
||||||
verboseLog("selected screen share source", sourceId);
|
verboseLog("selected screen share source", sourceId);
|
||||||
return true;
|
return true;
|
||||||
},
|
});
|
||||||
);
|
|
||||||
ipcMain.handle(ipcChannels.getVersion, () => app.getVersion());
|
ipcMain.handle(ipcChannels.getVersion, () => app.getVersion());
|
||||||
ipcMain.handle(ipcChannels.checkForUpdates, checkForUpdates);
|
ipcMain.handle(ipcChannels.checkForUpdates, checkForUpdates);
|
||||||
ipcMain.handle(ipcChannels.minimizeWindow, () => {
|
ipcMain.handle(ipcChannels.minimizeWindow, () => {
|
||||||
|
|
@ -226,7 +191,6 @@ async function createWindow() {
|
||||||
minWidth: 900,
|
minWidth: 900,
|
||||||
minHeight: 600,
|
minHeight: 600,
|
||||||
title: "Tensamin",
|
title: "Tensamin",
|
||||||
icon: getWindowIcon(),
|
|
||||||
frame: false,
|
frame: false,
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
|
|
@ -246,24 +210,18 @@ async function createWindow() {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
mainWindow.webContents.on(
|
mainWindow.webContents.on("console-message", (_event, level, message, line, sourceId) => {
|
||||||
"console-message",
|
|
||||||
(_event, level, message, line, sourceId) => {
|
|
||||||
const target = level >= 2 ? console.error : console.log;
|
const target = level >= 2 ? console.error : console.log;
|
||||||
target("[tensamin:renderer]", message, { level, line, sourceId });
|
target("[tensamin:renderer]", message, { level, line, sourceId });
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
mainWindow.webContents.on(
|
mainWindow.webContents.on("did-fail-load", (_event, errorCode, errorDescription, validatedURL) => {
|
||||||
"did-fail-load",
|
|
||||||
(_event, errorCode, errorDescription, validatedURL) => {
|
|
||||||
console.error("[tensamin:electron] renderer failed to load", {
|
console.error("[tensamin:electron] renderer failed to load", {
|
||||||
errorCode,
|
errorCode,
|
||||||
errorDescription,
|
errorDescription,
|
||||||
validatedURL,
|
validatedURL,
|
||||||
});
|
});
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
mainWindow.webContents.on("did-finish-load", () => {
|
mainWindow.webContents.on("did-finish-load", () => {
|
||||||
verboseLog("renderer finished loading", mainWindow?.webContents.getURL());
|
verboseLog("renderer finished loading", mainWindow?.webContents.getURL());
|
||||||
|
|
|
||||||
|
|
@ -3,21 +3,13 @@ import { createReadStream } from "node:fs";
|
||||||
import { mkdir, rm, writeFile } from "node:fs/promises";
|
import { mkdir, rm, writeFile } from "node:fs/promises";
|
||||||
import { basename, join } from "node:path";
|
import { basename, join } from "node:path";
|
||||||
import { app, net } from "electron";
|
import { app, net } from "electron";
|
||||||
import type {
|
import type { ReleaseArtifact, ReleaseMetadata, UpdateCheckResult } from "../shared/ipc.js";
|
||||||
ReleaseArtifact,
|
|
||||||
ReleaseMetadata,
|
|
||||||
UpdateCheckResult,
|
|
||||||
} from "../shared/ipc.js";
|
|
||||||
|
|
||||||
const metadataUrl = process.env.TENSAMIN_UPDATE_METADATA_URL;
|
const metadataUrl = process.env.TENSAMIN_UPDATE_METADATA_URL;
|
||||||
|
|
||||||
function compareSemver(left: string, right: string) {
|
function compareSemver(left: string, right: string) {
|
||||||
const leftParts = left
|
const leftParts = left.split(/[.-]/).map((part) => Number.parseInt(part, 10) || 0);
|
||||||
.split(/[.-]/)
|
const rightParts = right.split(/[.-]/).map((part) => Number.parseInt(part, 10) || 0);
|
||||||
.map((part) => Number.parseInt(part, 10) || 0);
|
|
||||||
const rightParts = right
|
|
||||||
.split(/[.-]/)
|
|
||||||
.map((part) => Number.parseInt(part, 10) || 0);
|
|
||||||
const length = Math.max(leftParts.length, rightParts.length);
|
const length = Math.max(leftParts.length, rightParts.length);
|
||||||
|
|
||||||
for (let index = 0; index < length; index += 1) {
|
for (let index = 0; index < length; index += 1) {
|
||||||
|
|
@ -50,9 +42,7 @@ function requestText(url: string): Promise<string> {
|
||||||
const request = net.request(url);
|
const request = net.request(url);
|
||||||
request.on("response", (response) => {
|
request.on("response", (response) => {
|
||||||
if (response.statusCode < 200 || response.statusCode >= 300) {
|
if (response.statusCode < 200 || response.statusCode >= 300) {
|
||||||
reject(
|
reject(new Error(`Update request failed with HTTP ${response.statusCode}.`));
|
||||||
new Error(`Update request failed with HTTP ${response.statusCode}.`),
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,9 +86,7 @@ async function sha256File(filePath: string) {
|
||||||
return hash.digest("hex");
|
return hash.digest("hex");
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectArtifact(
|
function selectArtifact(metadata: ReleaseMetadata): ReleaseArtifact | undefined {
|
||||||
metadata: ReleaseMetadata,
|
|
||||||
): ReleaseArtifact | undefined {
|
|
||||||
const platform = platformName();
|
const platform = platformName();
|
||||||
const arch = archName();
|
const arch = archName();
|
||||||
|
|
||||||
|
|
@ -114,26 +102,16 @@ export async function checkForUpdates(): Promise<UpdateCheckResult> {
|
||||||
return { available: false, currentVersion, latestVersion: currentVersion };
|
return { available: false, currentVersion, latestVersion: currentVersion };
|
||||||
}
|
}
|
||||||
|
|
||||||
const metadata = JSON.parse(
|
const metadata = JSON.parse(await requestText(metadataUrl)) as ReleaseMetadata;
|
||||||
await requestText(metadataUrl),
|
|
||||||
) as ReleaseMetadata;
|
|
||||||
const artifact = selectArtifact(metadata);
|
const artifact = selectArtifact(metadata);
|
||||||
|
|
||||||
if (isDevVersion(metadata.version) !== isDevVersion(currentVersion)) {
|
if (isDevVersion(metadata.version) !== isDevVersion(currentVersion)) {
|
||||||
return {
|
return { available: false, currentVersion, latestVersion: metadata.version };
|
||||||
available: false,
|
|
||||||
currentVersion,
|
|
||||||
latestVersion: metadata.version,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDevVersion(currentVersion)) {
|
if (isDevVersion(currentVersion)) {
|
||||||
if (!artifact || metadata.version === currentVersion) {
|
if (!artifact || metadata.version === currentVersion) {
|
||||||
return {
|
return { available: false, currentVersion, latestVersion: metadata.version };
|
||||||
available: false,
|
|
||||||
currentVersion,
|
|
||||||
latestVersion: metadata.version,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
@ -145,11 +123,7 @@ export async function checkForUpdates(): Promise<UpdateCheckResult> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!artifact || compareSemver(metadata.version, currentVersion) <= 0) {
|
if (!artifact || compareSemver(metadata.version, currentVersion) <= 0) {
|
||||||
return {
|
return { available: false, currentVersion, latestVersion: metadata.version };
|
||||||
available: false,
|
|
||||||
currentVersion,
|
|
||||||
latestVersion: metadata.version,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
@ -166,9 +140,7 @@ export async function downloadVerifiedArtifact(artifact: ReleaseArtifact) {
|
||||||
await mkdir(updatesDir, { recursive: true });
|
await mkdir(updatesDir, { recursive: true });
|
||||||
|
|
||||||
const destination = join(updatesDir, basename(artifact.name));
|
const destination = join(updatesDir, basename(artifact.name));
|
||||||
await writeFile(destination, await requestBuffer(artifact.url), {
|
await writeFile(destination, await requestBuffer(artifact.url), { mode: 0o600 });
|
||||||
mode: 0o600,
|
|
||||||
});
|
|
||||||
|
|
||||||
const actualHash = await sha256File(destination);
|
const actualHash = await sha256File(destination);
|
||||||
if (actualHash !== artifact.sha256) {
|
if (actualHash !== artifact.sha256) {
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
"build:mobile:raw": "tauri android build",
|
"build:mobile:raw": "tauri android build",
|
||||||
"dev:mobile": "if command -v nix >/dev/null 2>&1; then nix develop --command bun dev:mobile:raw; else bun dev:mobile:raw; fi",
|
"dev:mobile": "if command -v nix >/dev/null 2>&1; then nix develop --command bun dev:mobile:raw; else bun dev:mobile:raw; fi",
|
||||||
"build:mobile": "bun run render-version.ts && if command -v nix >/dev/null 2>&1; then nix develop --command bun build:mobile:raw; else bun build:mobile:raw; fi && bun run render-version.ts --unrender",
|
"build:mobile": "bun run render-version.ts && if command -v nix >/dev/null 2>&1; then nix develop --command bun build:mobile:raw; else bun build:mobile:raw; fi && bun run render-version.ts --unrender",
|
||||||
"gen-icons": "tauri icon ./logo.json && bun scripts/sync-electron-icons.ts",
|
"gen-icons": "tauri icon ./logo.json",
|
||||||
"format": "bunx prettier --write .",
|
"format": "bunx prettier --write .",
|
||||||
"lint": "eslint src"
|
"lint": "eslint src"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
import { copyFile, mkdir } from "node:fs/promises";
|
|
||||||
import { dirname, join, resolve } from "node:path";
|
|
||||||
import { fileURLToPath } from "node:url";
|
|
||||||
|
|
||||||
const scriptDir = dirname(fileURLToPath(import.meta.url));
|
|
||||||
const tauriDir = resolve(scriptDir, "..");
|
|
||||||
const clientDir = resolve(tauriDir, "../..");
|
|
||||||
const tauriIconsDir = join(tauriDir, "src-tauri", "icons");
|
|
||||||
const electronIconsDir = join(clientDir, "apps", "electron", "build", "icons");
|
|
||||||
|
|
||||||
const desktopIcons = [
|
|
||||||
"32x32.png",
|
|
||||||
"64x64.png",
|
|
||||||
"128x128.png",
|
|
||||||
"128x128@2x.png",
|
|
||||||
"icon.png",
|
|
||||||
"icon.ico",
|
|
||||||
"icon.icns",
|
|
||||||
];
|
|
||||||
|
|
||||||
await mkdir(electronIconsDir, { recursive: true });
|
|
||||||
|
|
||||||
await Promise.all(
|
|
||||||
desktopIcons.map((icon) =>
|
|
||||||
copyFile(join(tauriIconsDir, icon), join(electronIconsDir, icon)),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log(
|
|
||||||
`Synced ${desktopIcons.length} desktop icons to ${electronIconsDir}`,
|
|
||||||
);
|
|
||||||
Binary file not shown.
|
|
@ -10,7 +10,7 @@ const tsconfigRootDir = dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
ignores: ["**/dist/**", "**/node_modules/**"],
|
ignores: ["**/dist/**", "**/node_modules/**", "**/.tmp/**"],
|
||||||
},
|
},
|
||||||
js.configs.recommended,
|
js.configs.recommended,
|
||||||
...tseslint.configs.recommended,
|
...tseslint.configs.recommended,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "tensamin",
|
"name": "tensamin",
|
||||||
"version": "0.0.7",
|
"version": "0.0.6",
|
||||||
"private": true,
|
"private": true,
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/*",
|
"packages/*",
|
||||||
|
|
|
||||||
|
|
@ -26,9 +26,7 @@ type ElectronDesktopApi = {
|
||||||
media?: {
|
media?: {
|
||||||
getScreenShareCapabilities?: () => Promise<DesktopScreenShareCapabilities>;
|
getScreenShareCapabilities?: () => Promise<DesktopScreenShareCapabilities>;
|
||||||
listScreenShareSources?: () => Promise<DesktopScreenShareSource[]>;
|
listScreenShareSources?: () => Promise<DesktopScreenShareSource[]>;
|
||||||
listScreenShareAudioOutputs?: () => Promise<
|
listScreenShareAudioOutputs?: () => Promise<DesktopScreenShareAudioOutput[]>;
|
||||||
DesktopScreenShareAudioOutput[]
|
|
||||||
>;
|
|
||||||
selectScreenShareSource?: (sourceId: string) => Promise<boolean>;
|
selectScreenShareSource?: (sourceId: string) => Promise<boolean>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
# Information
|
|
||||||
|
|
||||||
All dev releases between two prod version get deleted upon creation of the latest prod release.
|
|
||||||
|
|
@ -60,9 +60,7 @@ const electronReleaseDir = "apps/electron/release";
|
||||||
|
|
||||||
const copyElectronArtifacts = () => {
|
const copyElectronArtifacts = () => {
|
||||||
if (!existsSync(electronReleaseDir)) {
|
if (!existsSync(electronReleaseDir)) {
|
||||||
console.warn(
|
console.warn(`Skipping Electron artifacts: ${electronReleaseDir} does not exist.`);
|
||||||
`Skipping Electron artifacts: ${electronReleaseDir} does not exist.`,
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -83,11 +81,7 @@ const artifacts = await Promise.all(
|
||||||
readdirSync(releasesDir)
|
readdirSync(releasesDir)
|
||||||
.map((file) => join(releasesDir, file))
|
.map((file) => join(releasesDir, file))
|
||||||
.filter((file) => statSync(file).isFile())
|
.filter((file) => statSync(file).isFile())
|
||||||
.filter(
|
.filter((file) => !file.endsWith("electron-release-metadata.json") && !file.endsWith("SHA256SUMS"))
|
||||||
(file) =>
|
|
||||||
!file.endsWith("electron-release-metadata.json") &&
|
|
||||||
!file.endsWith("SHA256SUMS"),
|
|
||||||
)
|
|
||||||
.map(async (filePath) => {
|
.map(async (filePath) => {
|
||||||
const name = filePath.split(/[\\/]/).at(-1)!;
|
const name = filePath.split(/[\\/]/).at(-1)!;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
"target": "ES2020",
|
"target": "ES2020",
|
||||||
"module": "nodenext",
|
"module": "nodenext",
|
||||||
"lib": ["ES2020"],
|
"lib": ["ES2020"],
|
||||||
"rootDir": ".",
|
"rootDir": "./scripts",
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
|
|
@ -12,6 +12,6 @@
|
||||||
"moduleResolution": "nodenext",
|
"moduleResolution": "nodenext",
|
||||||
"types": ["node"]
|
"types": ["node"]
|
||||||
},
|
},
|
||||||
"include": ["scripts", "eslint.config.ts"],
|
"include": ["scripts"],
|
||||||
"exclude": ["node_modules", "dist"]
|
"exclude": ["node_modules", "dist"]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue