mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
Add Bonfida import fix script and improve release workflow
This commit is contained in:
@@ -11,6 +11,10 @@ on:
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch: [x64, arm64]
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -20,24 +24,23 @@ jobs:
|
||||
with:
|
||||
# needed for git commit history changelog
|
||||
fetch-depth: 0
|
||||
- name: Setup Node.js v20
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 20
|
||||
- name: Install dependencies (with Node v20)
|
||||
run: yarn install --frozen-lockfile --ignore-engines
|
||||
# make sure the ipfs executable is executable
|
||||
- name: Download IPFS and set permissions (with Node v20)
|
||||
run: node electron/download-ipfs && sudo chmod +x bin/linux/ipfs
|
||||
|
||||
- name: Setup Node.js v22 for Electron build
|
||||
- name: Setup Node.js v22
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 22
|
||||
- name: Install dependencies (with Node v22)
|
||||
run: yarn install --frozen-lockfile --ignore-engines
|
||||
# make sure the ipfs executable is executable
|
||||
- name: Download IPFS and set permissions (with Node v22)
|
||||
run: node electron/download-ipfs && sudo chmod +x bin/linux/ipfs
|
||||
- name: Build React app (with Node v22)
|
||||
run: CI='' yarn build
|
||||
- name: Build Electron app for Linux (with Node v22)
|
||||
run: yarn electron:build:linux
|
||||
run: CI='' NODE_ENV=production yarn build
|
||||
- name: Build Electron app for Linux (arm64)
|
||||
if: ${{ matrix.arch == 'arm64' }}
|
||||
run: yarn electron:build:linux:arm64
|
||||
- name: Build Electron app for Linux (x64)
|
||||
if: ${{ matrix.arch == 'x64' }}
|
||||
run: yarn electron:build:linux:x64
|
||||
- name: List dist directory
|
||||
run: ls dist
|
||||
|
||||
@@ -46,14 +49,22 @@ jobs:
|
||||
run: node scripts/release-body > release-body.txt
|
||||
- uses: ncipollo/release-action@v1
|
||||
with:
|
||||
artifacts: 'dist/5chan*.AppImage,dist/5chan-html*.zip'
|
||||
artifacts: 'dist/5chan*.AppImage,dist/5chan*-arm64.AppImage,dist/5chan-html*.zip'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
replacesArtifacts: true
|
||||
bodyFile: "release-body.txt"
|
||||
omitBody: true
|
||||
allowUpdates: true
|
||||
|
||||
mac:
|
||||
runs-on: macos-15
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- runner: macos-15-intel # Intel x64
|
||||
arch: x64
|
||||
- runner: macos-latest # Apple Silicon arm64
|
||||
arch: arm64
|
||||
runs-on: ${{ matrix.runner }}
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
@@ -62,10 +73,14 @@ jobs:
|
||||
with:
|
||||
# needed for git commit history changelog
|
||||
fetch-depth: 0
|
||||
- name: Setup Node.js v20
|
||||
- name: Setup Node.js v22
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 20
|
||||
node-version: 22
|
||||
- name: Setup Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
# install missing dep for sqlite (use setup-python to avoid PEP 668 externally-managed-environment error)
|
||||
- uses: actions/setup-python@v5
|
||||
@@ -73,20 +88,22 @@ jobs:
|
||||
python-version: '3.12'
|
||||
- run: pip install setuptools
|
||||
|
||||
- name: Install dependencies (with Node v20)
|
||||
- name: Install dependencies (with Node v22)
|
||||
run: yarn install --frozen-lockfile --ignore-engines
|
||||
# make sure the ipfs executable is executable
|
||||
- name: Download IPFS and set permissions (with Node v20)
|
||||
- name: Download IPFS and set permissions (with Node v22)
|
||||
run: node electron/download-ipfs && sudo chmod +x bin/mac/ipfs
|
||||
|
||||
- name: Setup Node.js v22 for Electron build
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 22
|
||||
- name: Build React app (with Node v22)
|
||||
run: CI='' yarn build
|
||||
run: CI='' NODE_ENV=production yarn build
|
||||
- name: Build Electron app for Mac (with Node v22)
|
||||
run: yarn electron:build:mac
|
||||
env:
|
||||
CSC_IDENTITY_AUTO_DISCOVERY: 'false'
|
||||
run: |
|
||||
if [ "${{ matrix.arch }}" = "arm64" ]; then
|
||||
yarn electron:build:mac:arm64
|
||||
else
|
||||
yarn electron:build:mac:x64
|
||||
fi
|
||||
- name: List dist directory
|
||||
run: ls dist
|
||||
|
||||
@@ -95,10 +112,10 @@ jobs:
|
||||
run: node scripts/release-body > release-body.txt
|
||||
- uses: ncipollo/release-action@v1
|
||||
with:
|
||||
artifacts: 'dist/5chan*.dmg'
|
||||
artifacts: 'dist/5chan*.dmg,dist/5chan*-arm64.dmg'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
replacesArtifacts: true
|
||||
bodyFile: "release-body.txt"
|
||||
omitBody: true
|
||||
allowUpdates: true
|
||||
|
||||
windows:
|
||||
@@ -118,8 +135,8 @@ jobs:
|
||||
- name: Install dependencies (with Node v22) # --network-timeout and --network-concurrency are yarn v1 flags.
|
||||
run: yarn install --frozen-lockfile --network-timeout 100000 --network-concurrency 1
|
||||
- name: Build React app (with Node v22)
|
||||
run: yarn build
|
||||
- name: Build Electron app for Windows (with Node v22)
|
||||
run: npx cross-env NODE_ENV=production yarn build
|
||||
- name: Build Electron app for Windows (x64)
|
||||
run: yarn electron:build:windows
|
||||
- name: List dist directory
|
||||
run: dir dist
|
||||
@@ -132,7 +149,7 @@ jobs:
|
||||
artifacts: 'dist/5chan*.exe'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
replacesArtifacts: true
|
||||
bodyFile: "release-body.txt"
|
||||
omitBody: true
|
||||
allowUpdates: true
|
||||
|
||||
android:
|
||||
@@ -153,14 +170,14 @@ jobs:
|
||||
gradle-version: 8.9
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 20
|
||||
node-version: 22
|
||||
- run: sudo apt install -y apksigner zipalign
|
||||
|
||||
# install all dependencies (including devDependencies needed for React build)
|
||||
- name: Install dependencies (with Node v20)
|
||||
- name: Install dependencies (with Node v22)
|
||||
run: yarn install --frozen-lockfile --ignore-engines
|
||||
# build react app
|
||||
- run: CI='' yarn build
|
||||
- run: CI='' NODE_ENV=production yarn build
|
||||
# set android versionCode and versionName
|
||||
- run: sed -i "s/versionCode 1/versionCode $(git tag | wc -l)/" ./android/app/build.gradle
|
||||
- run: sed -i "s/versionName \"1.0\"/versionName \"$(node -e "console.log(require('./package.json').version)")\"/" ./android/app/build.gradle
|
||||
@@ -168,7 +185,7 @@ jobs:
|
||||
# build apk
|
||||
- run: npx cap sync android
|
||||
- run: cd android && gradle bundle
|
||||
- run: cd android && ./gradlew assembleRelease
|
||||
- run: cd android && ./gradlew assembleRelease --stacktrace
|
||||
# optimize apk
|
||||
- run: cd android/app/build/outputs/apk/release && zipalign 4 app-release-unsigned.apk app-release-unsigned-zip.apk
|
||||
# sign apk
|
||||
@@ -185,5 +202,31 @@ jobs:
|
||||
artifacts: 'dist/5chan*.apk'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
replacesArtifacts: true
|
||||
bodyFile: "release-body.txt"
|
||||
omitBody: true
|
||||
allowUpdates: true
|
||||
|
||||
finalize-release:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [linux, mac, windows, android]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Node.js v22
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 22
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile --ignore-engines
|
||||
- name: Generate final release body from GitHub assets
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_REPOSITORY: ${{ github.repository }}
|
||||
GITHUB_REF_NAME: ${{ github.ref_name }}
|
||||
run: node scripts/release-body > release-body.txt
|
||||
- name: Update release body only
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
allowUpdates: true
|
||||
bodyFile: "release-body.txt"
|
||||
|
||||
+11
-4
@@ -46,6 +46,7 @@
|
||||
"zustand": "4.4.3"
|
||||
},
|
||||
"scripts": {
|
||||
"postinstall": "node scripts/fix-bonfida-imports.js",
|
||||
"generate:assets": "node scripts/generate-asset-manifest.js",
|
||||
"prebuild": "yarn generate:assets",
|
||||
"prestart": "yarn generate:assets",
|
||||
@@ -61,8 +62,12 @@
|
||||
"electron:start": "concurrently \"cross-env BROWSER=none yarn start\" \"wait-on http://localhost:3000 && yarn electron\"",
|
||||
"electron:start:no-delete-data": "concurrently \"cross-env BROWSER=none yarn start\" \"wait-on http://localhost:3000 && yarn electron:no-delete-data\"",
|
||||
"electron:build:linux": "yarn build && yarn build:preload && electron-builder build --publish never -l",
|
||||
"electron:build:linux:x64": "yarn build:preload && electron-builder build --publish never -l --x64",
|
||||
"electron:build:linux:arm64": "yarn build:preload && electron-builder build --publish never -l --arm64",
|
||||
"electron:build:windows": "yarn build && yarn build:preload && electron-builder build --publish never -w",
|
||||
"electron:build:mac": "yarn build && yarn build:preload && electron-builder build --publish never -m",
|
||||
"electron:build:mac:x64": "yarn build:preload && electron-builder build --publish never -m --x64",
|
||||
"electron:build:mac:arm64": "yarn build:preload && electron-builder build --publish never -m --arm64",
|
||||
"electron:before": "yarn electron-rebuild && yarn electron:before:download-ipfs && yarn electron:before:delete-data",
|
||||
"electron:before:download-ipfs": "node electron/download-ipfs",
|
||||
"electron:before:delete-data": "rimraf .plebbit",
|
||||
@@ -114,6 +119,7 @@
|
||||
"isomorphic-fetch": "3.0.0",
|
||||
"jsdom": "27.3.0",
|
||||
"lint-staged": "12.3.8",
|
||||
"node-fetch": "3.3.2",
|
||||
"oxfmt": "0.20.0",
|
||||
"oxlint": "1.35.0",
|
||||
"progress": "2.0.3",
|
||||
@@ -127,6 +133,8 @@
|
||||
"wait-on": "9.0.3"
|
||||
},
|
||||
"resolutions": {
|
||||
"@bonfida/spl-name-service": "3.0.16",
|
||||
"@bonfida/sns-records": "0.0.1",
|
||||
"js-yaml": "4.1.1",
|
||||
"baseline-browser-mapping": "^2.9.11",
|
||||
"vite": "npm:rolldown-vite@7.3.1",
|
||||
@@ -153,12 +161,11 @@
|
||||
"appId": "5chan.desktop",
|
||||
"productName": "5chan",
|
||||
"icon": "public/icon.png",
|
||||
"asarUnpack": [
|
||||
"**/*.node"
|
||||
],
|
||||
"beforePack": "electron/before-pack.js",
|
||||
"afterAllArtifactBuild": "electron/after-all-artifact-build.cjs",
|
||||
"asarUnpack": [
|
||||
"node_modules/@bonfida/**/*",
|
||||
"node_modules/@solana/**/*"
|
||||
],
|
||||
"extraResources": [
|
||||
{
|
||||
"from": "bin/${os}",
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env node
|
||||
// Fix broken ESM imports in @bonfida/spl-name-service
|
||||
// The package ships with hardcoded ../node_modules/ paths that break in electron asar
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const rootDir = path.join(__dirname, '..');
|
||||
const bonfidaEsmDir = path.join(rootDir, 'node_modules/@bonfida/spl-name-service/dist/esm');
|
||||
const bonfidaCjsDir = path.join(rootDir, 'node_modules/@bonfida/spl-name-service/dist/cjs');
|
||||
|
||||
// Map of known packages to their correct import paths
|
||||
const packageMappings = {
|
||||
'@noble/hashes': (subpath) => {
|
||||
// ../node_modules/@noble/hashes/esm/sha256.js -> @noble/hashes/sha256
|
||||
if (subpath.includes('/sha256')) return '@noble/hashes/sha256';
|
||||
if (subpath.includes('/sha512')) return '@noble/hashes/sha512';
|
||||
return '@noble/hashes';
|
||||
},
|
||||
'@noble/curves': (subpath) => {
|
||||
// ../node_modules/@noble/curves/esm/ed25519.js -> @noble/curves/ed25519
|
||||
if (subpath.includes('/ed25519')) return '@noble/curves/ed25519';
|
||||
if (subpath.includes('/secp256k1')) return '@noble/curves/secp256k1';
|
||||
return '@noble/curves';
|
||||
},
|
||||
'@solana/spl-token': () => '@solana/spl-token',
|
||||
'@solana/web3.js': () => '@solana/web3.js',
|
||||
'@bonfida/sns-records': () => '@bonfida/sns-records',
|
||||
'@scure/base': () => '@scure/base',
|
||||
buffer: () => 'buffer',
|
||||
borsh: () => 'borsh',
|
||||
graphemesplit: () => 'graphemesplit',
|
||||
bs58: () => 'bs58',
|
||||
'ipaddr.js': () => 'ipaddr.js',
|
||||
punycode: () => 'punycode',
|
||||
};
|
||||
|
||||
// Generic function to fix node_modules imports
|
||||
function fixImportsInContent(content) {
|
||||
// Match patterns like from"../node_modules/PACKAGE/..." or from"./node_modules/PACKAGE/..."
|
||||
const importPattern = /from\s*["'](\.\.?\/node_modules\/((?:@[^\/]+\/[^\/]+|[^\/]+))([^"']*))["']/g;
|
||||
const sideEffectPattern = /import\s*["'](\.\.?\/node_modules\/((?:@[^\/]+\/[^\/]+|[^\/]+))([^"']*))["']/g;
|
||||
const requirePattern = /require\s*\(\s*["'](\.\.?\/node_modules\/((?:@[^\/]+\/[^\/]+|[^\/]+))([^"']*))["']\s*\)/g;
|
||||
|
||||
let modified = false;
|
||||
|
||||
const replaceImport = (match, fullPath, packageName, subpath) => {
|
||||
modified = true;
|
||||
const mapper = packageMappings[packageName];
|
||||
const correctImport = mapper ? mapper(subpath) : packageName;
|
||||
return `from"${correctImport}"`;
|
||||
};
|
||||
|
||||
const replaceSideEffect = (match, fullPath, packageName, subpath) => {
|
||||
modified = true;
|
||||
const mapper = packageMappings[packageName];
|
||||
const correctImport = mapper ? mapper(subpath) : packageName;
|
||||
return `import"${correctImport}"`;
|
||||
};
|
||||
|
||||
const replaceRequire = (match, fullPath, packageName, subpath) => {
|
||||
modified = true;
|
||||
const mapper = packageMappings[packageName];
|
||||
const correctImport = mapper ? mapper(subpath) : packageName;
|
||||
return `require("${correctImport}")`;
|
||||
};
|
||||
|
||||
let result = content;
|
||||
result = result.replace(importPattern, replaceImport);
|
||||
result = result.replace(sideEffectPattern, replaceSideEffect);
|
||||
result = result.replace(requirePattern, replaceRequire);
|
||||
|
||||
return { content: result, modified };
|
||||
}
|
||||
|
||||
function fixFile(filePath) {
|
||||
if (!fs.existsSync(filePath)) return false;
|
||||
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
const result = fixImportsInContent(content);
|
||||
|
||||
if (result.modified) {
|
||||
fs.writeFileSync(filePath, result.content);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function fixDirectory(dir) {
|
||||
if (!fs.existsSync(dir)) {
|
||||
console.log(`Directory not found: ${dir}`);
|
||||
return;
|
||||
}
|
||||
|
||||
let fixedCount = 0;
|
||||
|
||||
function walk(currentDir) {
|
||||
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
||||
|
||||
for (const entry of entries) {
|
||||
const fullPath = path.join(currentDir, entry.name);
|
||||
|
||||
if (entry.isDirectory() && entry.name !== 'node_modules') {
|
||||
walk(fullPath);
|
||||
} else if (entry.isFile() && /\.(m?js|cjs)$/.test(entry.name)) {
|
||||
if (fixFile(fullPath)) {
|
||||
fixedCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
walk(dir);
|
||||
return fixedCount;
|
||||
}
|
||||
|
||||
console.log('Fixing @bonfida/spl-name-service broken imports...');
|
||||
|
||||
const esmFixed = fixDirectory(bonfidaEsmDir);
|
||||
const cjsFixed = fixDirectory(bonfidaCjsDir);
|
||||
|
||||
console.log(`Fixed ${esmFixed} ESM files and ${cjsFixed} CJS files`);
|
||||
|
||||
// Also remove the nested node_modules that are no longer needed
|
||||
const nestedEsm = path.join(bonfidaEsmDir, 'node_modules');
|
||||
const nestedCjs = path.join(bonfidaCjsDir, 'node_modules');
|
||||
|
||||
if (fs.existsSync(nestedEsm)) {
|
||||
fs.rmSync(nestedEsm, { recursive: true });
|
||||
console.log('Removed nested ESM node_modules');
|
||||
}
|
||||
|
||||
if (fs.existsSync(nestedCjs)) {
|
||||
fs.rmSync(nestedCjs, { recursive: true });
|
||||
console.log('Removed nested CJS node_modules');
|
||||
}
|
||||
|
||||
console.log('Done!');
|
||||
+106
-22
@@ -1,34 +1,118 @@
|
||||
import {execSync} from 'child_process'
|
||||
import path from 'path'
|
||||
import {fileURLToPath} from 'url'
|
||||
import {readFileSync} from 'fs'
|
||||
import { execSync } from 'child_process';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { readFileSync, readdirSync } from 'fs';
|
||||
import fetch from 'node-fetch';
|
||||
|
||||
const dirname = path.join(path.dirname(fileURLToPath(import.meta.url)))
|
||||
const conventionalChangelog = path.join(dirname, '..', 'node_modules', '.bin', 'conventional-changelog')
|
||||
const packageJsonPath = path.join(dirname, '..', 'package.json')
|
||||
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'))
|
||||
const version = packageJson.version
|
||||
const dirname = path.join(path.dirname(fileURLToPath(import.meta.url)));
|
||||
const conventionalChangelog = path.join(dirname, '..', 'node_modules', '.bin', 'conventional-changelog');
|
||||
const version = JSON.parse(readFileSync(path.join(dirname, '..', 'package.json'), 'utf8')).version;
|
||||
|
||||
// sometimes release-count 1 is empty
|
||||
let releaseChangelog =
|
||||
execSync(`${conventionalChangelog} --preset angular --release-count 1`).toString() ||
|
||||
execSync(`${conventionalChangelog} --preset angular --release-count 2`).toString()
|
||||
// changelog (use last non-empty)
|
||||
let releaseChangelog =
|
||||
execSync(`${conventionalChangelog} --preset angular --release-count 1`).toString() ||
|
||||
execSync(`${conventionalChangelog} --preset angular --release-count 2`).toString();
|
||||
releaseChangelog = releaseChangelog.trim().replace(/\n\n+/g, '\n\n');
|
||||
|
||||
// format
|
||||
releaseChangelog = releaseChangelog.trim().replace(/\n\n+/g, '\n\n')
|
||||
// discover artifacts
|
||||
const distDir = path.join(dirname, '..', 'dist');
|
||||
let files = [];
|
||||
try {
|
||||
files = readdirSync(distDir);
|
||||
} catch {}
|
||||
|
||||
// In CI finalization, dist is empty. Prefer GitHub release assets when available.
|
||||
const getReleaseAssetNames = async () => {
|
||||
try {
|
||||
const token = process.env.GITHUB_TOKEN;
|
||||
const repo = process.env.GITHUB_REPOSITORY; // owner/repo
|
||||
const tag = process.env.GITHUB_REF_NAME || `v${version}`;
|
||||
if (!token || !repo || !tag) return [];
|
||||
const res = await fetch(`https://api.github.com/repos/${repo}/releases/tags/${tag}`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'User-Agent': '5chan-release-notes',
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
Accept: 'application/vnd.github+json',
|
||||
},
|
||||
});
|
||||
if (!res.ok) return [];
|
||||
const data = await res.json();
|
||||
return (data.assets || []).map((a) => a.name).filter(Boolean);
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
const remoteFiles = await getReleaseAssetNames();
|
||||
if (remoteFiles.length) {
|
||||
files = remoteFiles;
|
||||
}
|
||||
|
||||
const linkTo = (file) => `https://github.com/plebbit/5chan/releases/download/v${version}/${file}`;
|
||||
const has = (s, sub) => s.toLowerCase().includes(sub);
|
||||
const isArm = (s) => has(s, 'arm64') || has(s, 'aarch64');
|
||||
const isX64 = (s) => has(s, 'x64') || has(s, 'x86_64') || !isArm(s);
|
||||
|
||||
// buckets
|
||||
const androidApk = files.find((f) => f.endsWith('.apk'));
|
||||
const htmlZip = files.find((f) => f.includes('5chan-html') && f.endsWith('.zip'));
|
||||
|
||||
const linux = files.filter((f) => f.endsWith('.AppImage'));
|
||||
const mac = files.filter((f) => f.endsWith('.dmg'));
|
||||
const win = files.filter((f) => f.toLowerCase().endsWith('.exe'));
|
||||
|
||||
const linuxArm = linux.find(isArm);
|
||||
const linuxX64 = linux.find(isX64);
|
||||
const macArm = mac.find(isArm);
|
||||
const macX64 = mac.find(isX64);
|
||||
|
||||
const winSetupX64 = win.find((f) => has(f, 'setup') && isX64(f));
|
||||
const winPortableX64 = win.find((f) => has(f, 'portable') && isX64(f));
|
||||
|
||||
// small section builder without push()
|
||||
const section = (title, lines) => {
|
||||
const body = lines.filter(Boolean).join('\n');
|
||||
return body ? `### ${title}\n${body}` : '';
|
||||
};
|
||||
|
||||
const macSection = section('macOS', [
|
||||
macArm && `- Apple Silicon (arm64): [Download DMG](${linkTo(macArm)})`,
|
||||
macX64 && `- Intel (x64): [Download DMG](${linkTo(macX64)})`,
|
||||
mac.length > 0 &&
|
||||
`- If macOS shows "5chan.app is damaged and can't be opened. You should move it to the Trash.", run this in Terminal to fix it: \`xattr -dr com.apple.quarantine "/Applications/5chan.app"\` then open the app again.`,
|
||||
]);
|
||||
|
||||
const winSection = section('Windows', [
|
||||
winSetupX64 && `- Installer (x64): [Download EXE](${linkTo(winSetupX64)})`,
|
||||
winPortableX64 && `- Portable (x64): [Download EXE](${linkTo(winPortableX64)})`,
|
||||
win.length > 0 &&
|
||||
`- If Windows shows "Windows protected your PC" (SmartScreen), click "More info" then "Run anyway". To permanently allow, right-click the .exe → Properties → check "Unblock", or run in PowerShell: \`Unblock-File -Path .\\path\\to\\file.exe\`.`,
|
||||
]);
|
||||
|
||||
const linuxSection = section('Linux', [
|
||||
linuxArm && `- AppImage (arm64): [Download](${linkTo(linuxArm)})`,
|
||||
linuxX64 && `- AppImage (x64): [Download](${linkTo(linuxX64)})`,
|
||||
]);
|
||||
|
||||
const androidSection = section('Android', [androidApk && `- APK: [Download](${linkTo(androidApk)})`]);
|
||||
|
||||
const htmlSection = section('Static HTML build', [htmlZip && `- 5chan-html (zip): [Download](${linkTo(htmlZip)})`]);
|
||||
|
||||
const downloads = [macSection, winSection, linuxSection, androidSection, htmlSection].filter(Boolean).join('\n\n');
|
||||
|
||||
const releaseBody = `This version rebrands the app to 5chan, introducing a set of new features and several performance improvements.
|
||||
|
||||
- Web app: https://5chan.app
|
||||
- Decentralized web app: https://5chan.eth (only works on [Brave Browser](https://brave.com/) or via [IPFS Companion](https://docs.ipfs.tech/install/ipfs-companion/#prerequisites))
|
||||
- Decentralized web app via IPFS/IPNS gateways (works on any browser): [5chan.eth.limo](https://5chan.eth.limo), [5chan.eth.link](https://5chan.eth.link), [dweb.link/ipfs.io](https://dweb.link/ipns/5chan.eth)
|
||||
- Decentralized web app via IPFS node you run: https://5chan.eth (works on [Brave Browser](https://brave.com/) or use [IPFS Companion](https://docs.ipfs.tech/install/ipfs-companion/#prerequisites))
|
||||
|
||||
## Downloads
|
||||
|
||||
- Android app: [Download APK](https://github.com/plebbit/5chan/releases/download/v${version}/5chan-${version}.apk)
|
||||
- Linux app: [Download AppImage](https://github.com/plebbit/5chan/releases/download/v${version}/5chan-${version}.AppImage)
|
||||
- macOS app: [Download DMG](https://github.com/plebbit/5chan/releases/download/v${version}/5chan-${version}.dmg)
|
||||
- Windows app: [Download EXE](https://github.com/plebbit/5chan/releases/download/v${version}/5chan.Setup.${version}.exe)
|
||||
${downloads}
|
||||
|
||||
${releaseChangelog}`
|
||||
## Changes
|
||||
|
||||
console.log(releaseBody)
|
||||
${releaseChangelog}`;
|
||||
|
||||
console.log(releaseBody);
|
||||
|
||||
@@ -1017,18 +1017,18 @@
|
||||
bs58 "5.0.0"
|
||||
buffer "^6.0.3"
|
||||
|
||||
"@bonfida/spl-name-service@3.0.10":
|
||||
version "3.0.10"
|
||||
resolved "https://registry.yarnpkg.com/@bonfida/spl-name-service/-/spl-name-service-3.0.10.tgz#883f2e077eef7d91147f44ae383990a82479d5f8"
|
||||
integrity sha512-CrqlEDz43K9fPIVaUXn29OiMWZUOs3+sxU7zHrlPjjdXn9GrJSVao5gjmflfK6tcwLxSSGC4F4GOg5erSfyR/A==
|
||||
"@bonfida/spl-name-service@3.0.10", "@bonfida/spl-name-service@3.0.16":
|
||||
version "3.0.16"
|
||||
resolved "https://registry.yarnpkg.com/@bonfida/spl-name-service/-/spl-name-service-3.0.16.tgz#5ebcadbb1908af9348ff15c20a4e4fdc8a1408da"
|
||||
integrity sha512-Y47inKaoGYQ2gxykZsLepc0fNPMLWd5ycGQ6k2FiHvIzlY4trHijc7zr9TyDhB/eI9c3XTy5ItM01Izy5pIZ/A==
|
||||
dependencies:
|
||||
"@bonfida/sns-records" "0.0.1"
|
||||
"@noble/curves" "^1.4.0"
|
||||
"@scure/base" "^1.1.6"
|
||||
"@noble/curves" "^1.9.1"
|
||||
"@scure/base" "^1.2.5"
|
||||
"@solana/spl-token" "0.4.6"
|
||||
borsh "2.0.0"
|
||||
buffer "^6.0.3"
|
||||
graphemesplit "^2.4.4"
|
||||
graphemesplit "^2.6.0"
|
||||
ipaddr.js "^2.2.0"
|
||||
punycode "^2.3.1"
|
||||
|
||||
@@ -3732,7 +3732,7 @@
|
||||
dependencies:
|
||||
"@noble/hashes" "1.8.0"
|
||||
|
||||
"@noble/curves@^1.4.0", "@noble/curves@^1.4.2", "@noble/curves@~1.9.0":
|
||||
"@noble/curves@^1.4.0", "@noble/curves@^1.4.2", "@noble/curves@^1.9.1", "@noble/curves@~1.9.0":
|
||||
version "1.9.7"
|
||||
resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.9.7.tgz#79d04b4758a43e4bca2cbdc62e7771352fa6b951"
|
||||
integrity sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==
|
||||
@@ -4403,7 +4403,7 @@
|
||||
estree-walker "^2.0.2"
|
||||
picomatch "^4.0.2"
|
||||
|
||||
"@scure/base@^1.1.6", "@scure/base@~1.2.5":
|
||||
"@scure/base@^1.2.5", "@scure/base@~1.2.5":
|
||||
version "1.2.6"
|
||||
resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.2.6.tgz#ca917184b8231394dd8847509c67a0be522e59f6"
|
||||
integrity sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==
|
||||
@@ -6863,6 +6863,11 @@ dargs@^8.0.0:
|
||||
resolved "https://registry.yarnpkg.com/dargs/-/dargs-8.1.0.tgz#a34859ea509cbce45485e5aa356fef70bfcc7272"
|
||||
integrity sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==
|
||||
|
||||
data-uri-to-buffer@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e"
|
||||
integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==
|
||||
|
||||
data-urls@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-6.0.0.tgz#95a7943c8ac14c1d563b771f2621cc50e8ec7744"
|
||||
@@ -7960,6 +7965,14 @@ fdir@^6.5.0:
|
||||
resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350"
|
||||
integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==
|
||||
|
||||
fetch-blob@^3.1.2, fetch-blob@^3.1.4:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.2.0.tgz#f09b8d4bbd45adc6f0c20b7e787e793e309dcce9"
|
||||
integrity sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==
|
||||
dependencies:
|
||||
node-domexception "^1.0.0"
|
||||
web-streams-polyfill "^3.0.3"
|
||||
|
||||
figures@^3.0.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af"
|
||||
@@ -8086,6 +8099,13 @@ form-data@^4.0.0, form-data@^4.0.4:
|
||||
hasown "^2.0.2"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
formdata-polyfill@^4.0.10:
|
||||
version "4.0.10"
|
||||
resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423"
|
||||
integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==
|
||||
dependencies:
|
||||
fetch-blob "^3.1.2"
|
||||
|
||||
freeport-promise@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/freeport-promise/-/freeport-promise-2.0.0.tgz#11e4f81e24d680b88a20c15b2103551f4b6663d8"
|
||||
@@ -8425,7 +8445,7 @@ graceful-fs@^4.1.10, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.11
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
|
||||
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
|
||||
|
||||
graphemesplit@^2.4.4:
|
||||
graphemesplit@^2.6.0:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/graphemesplit/-/graphemesplit-2.6.0.tgz#548ec986e83dcdfec31adf5c98b282985077ce46"
|
||||
integrity sha512-rG9w2wAfkpg0DILa1pjnjNfucng3usON360shisqIMUBw/87pojcBSrHmeE4UwryAuBih7g8m1oilf5/u8EWdQ==
|
||||
@@ -11466,6 +11486,20 @@ node-datachannel@^0.29.0:
|
||||
dependencies:
|
||||
prebuild-install "^7.1.3"
|
||||
|
||||
node-domexception@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5"
|
||||
integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==
|
||||
|
||||
node-fetch@3.3.2:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.3.2.tgz#d1e889bacdf733b4ff3b2b243eb7a12866a0b78b"
|
||||
integrity sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==
|
||||
dependencies:
|
||||
data-uri-to-buffer "^4.0.0"
|
||||
fetch-blob "^3.1.4"
|
||||
formdata-polyfill "^4.0.10"
|
||||
|
||||
node-fetch@^2.6.1, node-fetch@^2.6.11, node-fetch@^2.6.7, node-fetch@^2.7.0:
|
||||
version "2.7.0"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
|
||||
@@ -14904,6 +14938,11 @@ web-namespaces@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-2.0.1.tgz#1010ff7c650eccb2592cebeeaf9a1b253fd40692"
|
||||
integrity sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==
|
||||
|
||||
web-streams-polyfill@^3.0.3:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz#2073b91a2fdb1fbfbd401e7de0ac9f8214cecb4b"
|
||||
integrity sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==
|
||||
|
||||
webcrypto-core@^1.8.0:
|
||||
version "1.8.1"
|
||||
resolved "https://registry.yarnpkg.com/webcrypto-core/-/webcrypto-core-1.8.1.tgz#09d5bd8a9c48e9fbcaf412e06b1ff1a57514ce86"
|
||||
|
||||
Reference in New Issue
Block a user