CI/CD & auto-updates first try pls

This commit is contained in:
2026-09-01 01:47:04 +08:00
parent 820e9f928d
commit bb458a50c7
11 changed files with 947 additions and 1483 deletions
+67
View File
@@ -0,0 +1,67 @@
name: Staging
on:
push:
branches: [staging]
permissions:
contents: read
jobs:
changes:
runs-on: ubuntu-latest
outputs:
desktop: ${{ steps.filter.outputs.desktop }}
server: ${{ steps.filter.outputs.server }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: filter
with:
base: ${{ github.ref }}
filters: |
desktop:
- 'src/**'
- 'src-tauri/**'
- 'package.json'
- 'bun.lock'
- 'svelte.config.js'
- 'tsconfig.json'
- 'vite.config.js'
- 'Cargo.toml'
- 'Cargo.lock'
- 'src-common/**'
- '.github/workflows/**'
server:
- 'src-server/**'
- 'Dockerfile'
- 'Cargo.toml'
- 'Cargo.lock'
- 'src-common/**'
- '.github/workflows/**'
desktop:
needs: changes
if: needs.changes.outputs.desktop == 'true'
runs-on: macos-15
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- uses: dtolnay/rust-toolchain@stable
- run: bun install --frozen-lockfile
- run: bun run check
- run: cargo check --locked --package friendolls
server:
needs: changes
if: needs.changes.outputs.server == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- run: cargo test --locked --package friendolls-server
- name: Ensure the production image builds
uses: docker/build-push-action@v6
with:
context: .
push: false
+97
View File
@@ -0,0 +1,97 @@
name: Release
on:
push:
branches: [release]
permissions:
contents: write
packages: write
jobs:
changes:
runs-on: ubuntu-latest
outputs:
desktop: ${{ steps.filter.outputs.desktop }}
server: ${{ steps.filter.outputs.server }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: filter
with:
base: ${{ github.ref }}
filters: |
desktop:
- 'src/**'
- 'src-tauri/**'
- 'package.json'
- 'bun.lock'
- 'svelte.config.js'
- 'tsconfig.json'
- 'vite.config.js'
- 'Cargo.toml'
- 'Cargo.lock'
- 'src-common/**'
- '.github/workflows/**'
server:
- 'src-server/**'
- 'Dockerfile'
- 'Cargo.toml'
- 'Cargo.lock'
- 'src-common/**'
- '.github/workflows/**'
desktop:
needs: changes
if: needs.changes.outputs.desktop == 'true'
strategy:
fail-fast: false
matrix:
include:
- platform: macos-15
rust_target: aarch64-apple-darwin
args: --target aarch64-apple-darwin
- platform: macos-15-intel
rust_target: x86_64-apple-darwin
args: --target x86_64-apple-darwin
- platform: windows-latest
rust_target: ""
args: ""
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.rust_target }}
- run: bun install --frozen-lockfile
- name: Build and upload Tauri bundles
uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
with:
tagName: v__VERSION__
releaseName: v__VERSION__
releaseBody: See the "Assets" below for downloads.
releaseDraft: false
prerelease: false
args: ${{ matrix.args }}
server:
needs: changes
if: needs.changes.outputs.server == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ghcr.io/${{ github.repository_owner }}/friendolls-server:latest
Generated
+348 -5
View File
@@ -59,6 +59,15 @@ version = "1.0.102"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
[[package]]
name = "arbitrary"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
dependencies = [
"derive_arbitrary",
]
[[package]]
name = "async-broadcast"
version = "0.7.2"
@@ -878,6 +887,17 @@ dependencies = [
"serde_core",
]
[[package]]
name = "derive_arbitrary"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.117",
]
[[package]]
name = "derive_more"
version = "2.1.1"
@@ -1242,6 +1262,16 @@ dependencies = [
"rustc_version",
]
[[package]]
name = "filetime"
version = "0.2.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759"
dependencies = [
"cfg-if",
"libc",
]
[[package]]
name = "find-msvc-tools"
version = "0.1.9"
@@ -1348,6 +1378,7 @@ dependencies = [
"tauri-build",
"tauri-plugin-dialog",
"tauri-plugin-opener",
"tauri-plugin-updater",
"tauri-specta",
"tokio",
"tokio-tungstenite 0.28.0",
@@ -1945,6 +1976,21 @@ dependencies = [
"want",
]
[[package]]
name = "hyper-rustls"
version = "0.27.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f"
dependencies = [
"http",
"hyper",
"hyper-util",
"rustls",
"tokio",
"tokio-rustls",
"tower-service",
]
[[package]]
name = "hyper-util"
version = "0.1.20"
@@ -1963,9 +2009,11 @@ dependencies = [
"percent-encoding",
"pin-project-lite",
"socket2",
"system-configuration",
"tokio",
"tower-service",
"tracing",
"windows-registry",
]
[[package]]
@@ -2241,6 +2289,36 @@ dependencies = [
"windows-sys 0.45.0",
]
[[package]]
name = "jni"
version = "0.22.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498"
dependencies = [
"cfg-if",
"combine",
"jni-macros",
"jni-sys 0.4.1",
"log",
"simd_cesu8",
"thiserror 2.0.18",
"walkdir",
"windows-link 0.2.1",
]
[[package]]
name = "jni-macros"
version = "0.22.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3"
dependencies = [
"proc-macro2",
"quote",
"rustc_version",
"simd_cesu8",
"syn 2.0.117",
]
[[package]]
name = "jni-sys"
version = "0.3.1"
@@ -2506,6 +2584,12 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "minisign-verify"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22f9645cb765ea72b8111f36c522475d2daa0d22c957a9826437e97534bc4e9e"
[[package]]
name = "miniz_oxide"
version = "0.8.9"
@@ -2822,6 +2906,18 @@ dependencies = [
"objc2-core-foundation",
]
[[package]]
name = "objc2-osa-kit"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f112d1746737b0da274ef79a23aac283376f335f4095a083a267a082f21db0c0"
dependencies = [
"bitflags 2.13.0",
"objc2",
"objc2-app-kit",
"objc2-foundation",
]
[[package]]
name = "objc2-quartz-core"
version = "0.3.2"
@@ -2897,6 +2993,12 @@ dependencies = [
"pathdiff",
]
[[package]]
name = "openssl-probe"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
[[package]]
name = "option-ext"
version = "0.2.0"
@@ -2913,6 +3015,20 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "osakit"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "732c71caeaa72c065bb69d7ea08717bd3f4863a4f451402fc9513e29dbd5261b"
dependencies = [
"objc2",
"objc2-foundation",
"objc2-osa-kit",
"serde",
"serde_json",
"thiserror 2.0.18",
]
[[package]]
name = "pango"
version = "0.18.3"
@@ -3452,15 +3568,20 @@ dependencies = [
"http-body",
"http-body-util",
"hyper",
"hyper-rustls",
"hyper-util",
"js-sys",
"log",
"percent-encoding",
"pin-project-lite",
"rustls",
"rustls-pki-types",
"rustls-platform-verifier",
"serde",
"serde_json",
"sync_wrapper",
"tokio",
"tokio-rustls",
"tokio-util",
"tower",
"tower-http",
@@ -3572,6 +3693,18 @@ dependencies = [
"zeroize",
]
[[package]]
name = "rustls-native-certs"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d"
dependencies = [
"openssl-probe",
"rustls-pki-types",
"schannel",
"security-framework",
]
[[package]]
name = "rustls-pki-types"
version = "1.15.1"
@@ -3581,6 +3714,33 @@ dependencies = [
"zeroize",
]
[[package]]
name = "rustls-platform-verifier"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0"
dependencies = [
"core-foundation 0.10.1",
"core-foundation-sys",
"jni 0.22.4",
"log",
"once_cell",
"rustls",
"rustls-native-certs",
"rustls-platform-verifier-android",
"rustls-webpki",
"security-framework",
"security-framework-sys",
"webpki-root-certs",
"windows-sys 0.61.2",
]
[[package]]
name = "rustls-platform-verifier-android"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
[[package]]
name = "rustls-webpki"
version = "0.103.13"
@@ -3613,6 +3773,15 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "schannel"
version = "0.1.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939"
dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "schemars"
version = "0.8.22"
@@ -3670,6 +3839,29 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "security-framework"
version = "3.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
dependencies = [
"bitflags 2.13.0",
"core-foundation 0.10.1",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework-sys"
version = "2.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "selectors"
version = "0.36.1"
@@ -3951,6 +4143,22 @@ version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214"
[[package]]
name = "simd_cesu8"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520"
dependencies = [
"rustc_version",
"simdutf8",
]
[[package]]
name = "simdutf8"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
[[package]]
name = "siphasher"
version = "1.0.3"
@@ -4388,6 +4596,27 @@ dependencies = [
"syn 2.0.117",
]
[[package]]
name = "system-configuration"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b"
dependencies = [
"bitflags 2.13.0",
"core-foundation 0.9.4",
"system-configuration-sys",
]
[[package]]
name = "system-configuration-sys"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "system-deps"
version = "6.2.2"
@@ -4419,7 +4648,7 @@ dependencies = [
"gdkwayland-sys",
"gdkx11-sys",
"gtk",
"jni",
"jni 0.21.1",
"libc",
"log",
"ndk",
@@ -4452,6 +4681,17 @@ dependencies = [
"syn 2.0.117",
]
[[package]]
name = "tar"
version = "0.4.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840"
dependencies = [
"filetime",
"libc",
"xattr",
]
[[package]]
name = "target-lexicon"
version = "0.12.16"
@@ -4475,7 +4715,7 @@ dependencies = [
"gtk",
"heck 0.5.0",
"http",
"jni",
"jni 0.21.1",
"libc",
"log",
"mime",
@@ -4652,6 +4892,39 @@ dependencies = [
"zbus",
]
[[package]]
name = "tauri-plugin-updater"
version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b28d8cabdeb0564f03ae261963de4bc3d98321cd3d213e76a81b7d344e5df606"
dependencies = [
"base64 0.22.1",
"dirs",
"flate2",
"futures-util",
"http",
"infer",
"log",
"minisign-verify",
"osakit",
"percent-encoding",
"reqwest",
"rustls",
"semver",
"serde",
"serde_json",
"tar",
"tauri",
"tauri-plugin",
"tempfile",
"thiserror 2.0.18",
"time",
"tokio",
"url",
"windows-sys 0.60.2",
"zip",
]
[[package]]
name = "tauri-runtime"
version = "2.11.2"
@@ -4662,7 +4935,7 @@ dependencies = [
"dpi",
"gtk",
"http",
"jni",
"jni 0.21.1",
"objc2",
"objc2-ui-kit",
"objc2-web-kit",
@@ -4685,7 +4958,7 @@ checksum = "b83849ee63ecb27a8e8d0fe51915ca215076914aca43f96db1179f0f415f6cd9"
dependencies = [
"gtk",
"http",
"jni",
"jni 0.21.1",
"log",
"objc2",
"objc2-app-kit",
@@ -4925,6 +5198,16 @@ dependencies = [
"syn 2.0.117",
]
[[package]]
name = "tokio-rustls"
version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61"
dependencies = [
"rustls",
"tokio",
]
[[package]]
name = "tokio-stream"
version = "0.1.19"
@@ -5616,6 +5899,15 @@ dependencies = [
"libwebp-sys",
]
[[package]]
name = "webpki-root-certs"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b96554aa2acc8ccdb7e1c9a58a7a68dd5d13bccc69cd124cb09406db612a1c9b"
dependencies = [
"rustls-pki-types",
]
[[package]]
name = "webpki-roots"
version = "0.26.11"
@@ -5876,6 +6168,17 @@ dependencies = [
"windows-link 0.1.3",
]
[[package]]
name = "windows-registry"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720"
dependencies = [
"windows-link 0.2.1",
"windows-result 0.4.1",
"windows-strings 0.5.1",
]
[[package]]
name = "windows-result"
version = "0.2.0"
@@ -5894,6 +6197,15 @@ dependencies = [
"windows-link 0.1.3",
]
[[package]]
name = "windows-result"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
dependencies = [
"windows-link 0.2.1",
]
[[package]]
name = "windows-strings"
version = "0.1.0"
@@ -5913,6 +6225,15 @@ dependencies = [
"windows-link 0.1.3",
]
[[package]]
name = "windows-strings"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
dependencies = [
"windows-link 0.2.1",
]
[[package]]
name = "windows-sys"
version = "0.45.0"
@@ -6295,7 +6616,7 @@ dependencies = [
"gtk",
"http",
"javascriptcore-rs",
"jni",
"jni 0.21.1",
"libc",
"ndk",
"objc2",
@@ -6342,6 +6663,16 @@ dependencies = [
"pkg-config",
]
[[package]]
name = "xattr"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156"
dependencies = [
"libc",
"rustix",
]
[[package]]
name = "yoke"
version = "0.8.3"
@@ -6506,6 +6837,18 @@ dependencies = [
"syn 2.0.117",
]
[[package]]
name = "zip"
version = "4.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "caa8cd6af31c3b31c6631b8f483848b91589021b28fffe50adada48d4f4d2ed1"
dependencies = [
"arbitrary",
"crc32fast",
"indexmap 2.14.0",
"memchr",
]
[[package]]
name = "zmij"
version = "1.0.21"
+25
View File
@@ -0,0 +1,25 @@
FROM rust:1-alpine AS builder
WORKDIR /app
RUN apk add --no-cache build-base musl-dev
COPY Cargo.toml Cargo.lock ./
COPY src-common/Cargo.toml src-common/Cargo.toml
COPY src-server/Cargo.toml src-server/Cargo.toml
COPY src-tauri/Cargo.toml src-tauri/Cargo.toml
COPY src-tauri/src/lib.rs src-tauri/src/lib.rs
COPY src-common/src src-common/src
COPY src-server/src src-server/src
RUN cargo build --locked --release --package friendolls-server
FROM alpine:3.23.5
RUN adduser -u 10001 -D friendolls
RUN mkdir /app
COPY --from=builder /app/target/release/friendolls-server /app/friendolls-server
USER friendolls
ENV BIND_ADDR=0.0.0.0:3000
EXPOSE 3000
ENTRYPOINT ["/app/friendolls-server"]
+339 -1478
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -16,6 +16,7 @@
"@tailwindcss/vite": "^4.3.3",
"@tauri-apps/api": "^2",
"@tauri-apps/plugin-opener": "^2",
"@tauri-apps/plugin-updater": "~2",
"tailwindcss": "^4.3.3",
"three": "^0.185.1"
},
+3
View File
@@ -61,3 +61,6 @@ windows = { version = "0.58", features = [
objc2 = "0.6.3"
objc2-app-kit = "0.3.2"
objc2-foundation = "0.3.2"
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
tauri-plugin-updater = "2"
+6
View File
@@ -0,0 +1,6 @@
{
"identifier": "desktop-capability",
"platforms": ["macOS", "windows"],
"windows": ["main"],
"permissions": ["updater:default"]
}
+3
View File
@@ -13,12 +13,14 @@ mod scene_configuration;
mod skins;
mod ufa;
mod ui;
mod updater;
mod user;
use tauri::Manager;
async fn launch_app(app: &tauri::App) -> Result<(), Box<dyn std::error::Error>> {
let handle = app.handle();
updater::init(handle).await;
db::init(handle).await?;
scene_configuration::init(handle).await?;
keypair::init(handle).await?;
@@ -47,6 +49,7 @@ pub fn run() {
.expect("Failed to export TypeScript bindings");
tauri::Builder::default()
.plugin(tauri_plugin_updater::Builder::new().build())
.plugin(tauri_plugin_dialog::init())
.plugin(tauri_plugin_opener::init())
.invoke_handler(specta_builder.invoke_handler())
+49
View File
@@ -0,0 +1,49 @@
use tauri::AppHandle;
use tauri_plugin_updater::UpdaterExt;
pub async fn init(app: &AppHandle) {
update_app(app).await
}
async fn update_app(app: &AppHandle) {
if let Some(update) = match match app.updater() {
Ok(it) => it,
Err(err) => {
println!("failed to get updater: {err:?}");
return;
}
}
.check()
.await
{
Ok(it) => it,
Err(err) => {
println!("failed to check for update: {err:?}");
return;
}
} {
let mut downloaded = 0;
match update
.download_and_install(
|chunk_length, content_length| {
downloaded += chunk_length;
println!("downloaded {downloaded} from {content_length:?}");
},
|| {
println!("download finished");
},
)
.await
{
Ok(it) => it,
Err(err) => {
println!("failed to install update: {err:?}");
return;
}
};
println!("update installed");
app.restart();
}
}
+9
View File
@@ -18,6 +18,7 @@
"bundle": {
"active": true,
"targets": "all",
"createUpdaterArtifacts": true,
"icon": [
"icons/32x32.png",
"icons/128x128.png",
@@ -25,5 +26,13 @@
"icons/icon.icns",
"icons/icon.ico"
]
},
"plugins": {
"updater": {
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEUzNTFBOTEwMDZBNTExOEQKUldTTkVhVUdFS2xSNHgyK0NiYmZXTy82RlhIYzVxNzNvdHZ5eitiSkozSzU0bm13R0t3QUtnd0oK",
"endpoints": [
"https://github.com/wind-explorer/friendolls/releases/latest/download/latest.json"
]
}
}
}