mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-05 00:54:56 +00:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
439ed14b78 | ||
|
|
0d98eb5e83 | ||
|
|
a16471c185 | ||
|
|
8bceece5b1 | ||
|
|
64827f771c | ||
|
|
80dc0e8271 | ||
|
|
5c4058cd73 | ||
|
|
12bfbf1db0 | ||
|
|
6da10f9a93 | ||
|
|
6977b0a948 | ||
|
|
1fbb462389 | ||
|
|
fee86304ae | ||
|
|
153c1b2c55 | ||
|
|
67be1fb47f | ||
|
|
4a3caaf766 | ||
|
|
6fcdd015aa | ||
|
|
835e7c434e | ||
|
|
7dbb85c8c2 | ||
|
|
752e697c6a |
@@ -11,7 +11,7 @@ PORT=3010
|
||||
# AFFINE_SERVER_EXTERNAL_URL=https://affine.yourdomain.com
|
||||
|
||||
# position of the database data to persist
|
||||
DB_DATA_LOCATION=~/.affine/self-host/postgres
|
||||
DB_DATA_LOCATION=~/.affine/self-host/postgres/pgdata
|
||||
# position of the upload data(images, files, etc.) to persist
|
||||
UPLOAD_LOCATION=~/.affine/self-host/storage
|
||||
# position of the configuration files to persist
|
||||
|
||||
@@ -19,6 +19,7 @@ services:
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- REDIS_SERVER_HOST=redis
|
||||
- DATABASE_URL=postgresql://${DB_USERNAME}:${DB_PASSWORD}@postgres:5432/${DB_DATABASE:-affine}
|
||||
restart: unless-stopped
|
||||
|
||||
@@ -33,6 +34,7 @@ services:
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- REDIS_SERVER_HOST=redis
|
||||
- DATABASE_URL=postgresql://${DB_USERNAME}:${DB_PASSWORD}@postgres:5432/${DB_DATABASE:-affine}
|
||||
depends_on:
|
||||
postgres:
|
||||
11
.github/actions/build-rust/action.yml
vendored
11
.github/actions/build-rust/action.yml
vendored
@@ -34,15 +34,10 @@ runs:
|
||||
echo "TARGET_CC=clang" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Cache cargo
|
||||
uses: actions/cache@v4
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry/index/
|
||||
~/.cargo/registry/cache/
|
||||
~/.cargo/git/db/
|
||||
~/.napi-rs
|
||||
target/${{ inputs.target }}
|
||||
key: stable-${{ inputs.target }}-cargo-cache
|
||||
save-if: ${{ github.ref_name == 'canary' }}
|
||||
shared-key: ${{ inputs.target }}-inputs.package
|
||||
- name: Build
|
||||
shell: bash
|
||||
run: |
|
||||
|
||||
17
.github/workflows/build-test.yml
vendored
17
.github/workflows/build-test.yml
vendored
@@ -31,14 +31,14 @@ jobs:
|
||||
name: Optimize CI
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
skip: ${{ steps.graphite.outputs.skip }}
|
||||
skip: ${{ steps.check_skip.outputs.skip }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Graphite CI Optimizer
|
||||
uses: withgraphite/graphite-ci-action@main
|
||||
id: graphite
|
||||
id: check_skip
|
||||
with:
|
||||
token: ${{ secrets.GRAPHITE_CI_OPTIMIZER_TOKEN }}
|
||||
graphite_token: ${{ secrets.GRAPHITE_CI_OPTIMIZER_TOKEN }}
|
||||
|
||||
analyze:
|
||||
name: Analyze
|
||||
@@ -311,6 +311,8 @@ jobs:
|
||||
build-server-native:
|
||||
name: Build Server native
|
||||
runs-on: ubuntu-latest
|
||||
needs: optimize_ci
|
||||
if: needs.optimize_ci.outputs.skip == 'false'
|
||||
env:
|
||||
CARGO_PROFILE_RELEASE_DEBUG: '1'
|
||||
steps:
|
||||
@@ -335,7 +337,8 @@ jobs:
|
||||
build-electron-renderer:
|
||||
name: Build @affine/electron renderer
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
needs: optimize_ci
|
||||
if: needs.optimize_ci.outputs.skip == 'false'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Node.js
|
||||
@@ -425,6 +428,8 @@ jobs:
|
||||
rust-test:
|
||||
name: Run native tests
|
||||
runs-on: ubuntu-latest
|
||||
needs: optimize_ci
|
||||
if: needs.optimize_ci.outputs.skip == 'false'
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
steps:
|
||||
@@ -436,7 +441,7 @@ jobs:
|
||||
uses: taiki-e/install-action@nextest
|
||||
|
||||
- name: Run tests
|
||||
run: cargo nextest run --release
|
||||
run: cargo nextest run --release --no-fail-fast
|
||||
|
||||
copilot-api-test:
|
||||
name: Server Copilot Api Test
|
||||
@@ -826,6 +831,8 @@ jobs:
|
||||
|
||||
test-build-mobile-app:
|
||||
uses: ./.github/workflows/release-mobile.yml
|
||||
needs: optimize_ci
|
||||
if: needs.optimize_ci.outputs.skip == 'false'
|
||||
with:
|
||||
build-type: canary
|
||||
build-target: development
|
||||
|
||||
10
.github/workflows/release-desktop.yml
vendored
10
.github/workflows/release-desktop.yml
vendored
@@ -441,7 +441,7 @@ jobs:
|
||||
node-version: 20
|
||||
- name: Copy Selfhost Release Files
|
||||
run: |
|
||||
cp ./.docker/selfhost/compose.yaml ./release/docker-compose.yaml
|
||||
cp ./.docker/selfhost/compose.yml ./release/docker-compose.yml
|
||||
cp ./.docker/selfhost/.env.example ./release/.env.example
|
||||
- name: Generate Release yml
|
||||
run: |
|
||||
@@ -456,7 +456,9 @@ jobs:
|
||||
body: ''
|
||||
draft: ${{ github.event.inputs.is-draft }}
|
||||
prerelease: ${{ github.event.inputs.is-pre-release }}
|
||||
files: ./release/*
|
||||
files: |
|
||||
./release/*
|
||||
./release/.env.example
|
||||
- name: Create Nightly Release Draft
|
||||
if: ${{ github.ref_type == 'branch' }}
|
||||
uses: softprops/action-gh-release@v2
|
||||
@@ -471,4 +473,6 @@ jobs:
|
||||
body: ''
|
||||
draft: false
|
||||
prerelease: true
|
||||
files: ./release/*
|
||||
files: |
|
||||
./release/*
|
||||
./release/.env.example
|
||||
|
||||
11
.github/workflows/release-mobile.yml
vendored
11
.github/workflows/release-mobile.yml
vendored
@@ -137,6 +137,9 @@ jobs:
|
||||
electron-install: false
|
||||
hard-link-nm: false
|
||||
enableScripts: false
|
||||
- uses: maxim-lobanov/setup-xcode@v1
|
||||
with:
|
||||
xcode-version: latest-stable
|
||||
- name: Cap sync
|
||||
run: yarn workspace @affine/ios cap sync
|
||||
- name: Signing By Apple Developer ID
|
||||
@@ -145,13 +148,15 @@ jobs:
|
||||
with:
|
||||
p12-file-base64: ${{ secrets.CERTIFICATES_P12_MOBILE }}
|
||||
p12-password: ${{ secrets.CERTIFICATES_P12_PASSWORD_MOBILE }}
|
||||
- uses: maxim-lobanov/setup-xcode@v1
|
||||
with:
|
||||
xcode-version: latest-stable
|
||||
- name: Setup Rust
|
||||
uses: ./.github/actions/setup-rust
|
||||
with:
|
||||
targets: 'aarch64-apple-ios'
|
||||
- name: Build Rust
|
||||
run: |
|
||||
brew install swiftformat
|
||||
cargo build -p affine_mobile_native --lib --release --target aarch64-apple-ios
|
||||
cargo run -p affine_mobile_native --bin uniffi-bindgen generate --library target/aarch64-apple-ios/release/libaffine_mobile_native.a --language swift --out-dir packages/frontend/apps/ios/App/App/uniffi
|
||||
- name: Testflight
|
||||
if: ${{ env.BUILD_TYPE != 'stable' }}
|
||||
working-directory: packages/frontend/apps/ios/App
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
.vscode
|
||||
.yarnrc.yml
|
||||
.docker
|
||||
**/.storybook
|
||||
|
||||
# compiled output
|
||||
.coverage
|
||||
@@ -33,5 +34,3 @@ packages/frontend/graphql/src/graphql/index.ts
|
||||
packages/frontend/graphql/src/schema.ts
|
||||
packages/frontend/apps/android/App/app/build/**
|
||||
blocksuite/tests-legacy/snapshots
|
||||
**/.storybook
|
||||
**/.coverage
|
||||
|
||||
169
Cargo.lock
generated
169
Cargo.lock
generated
@@ -33,6 +33,16 @@ name = "affine_mobile_native"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"affine_common",
|
||||
"affine_nbstore",
|
||||
"anyhow",
|
||||
"base64-simd",
|
||||
"chrono",
|
||||
"dashmap",
|
||||
"homedir",
|
||||
"objc2",
|
||||
"objc2-foundation",
|
||||
"sqlx",
|
||||
"thiserror 2.0.9",
|
||||
"uniffi",
|
||||
]
|
||||
|
||||
@@ -64,6 +74,7 @@ dependencies = [
|
||||
"napi-derive",
|
||||
"sqlx",
|
||||
"tokio",
|
||||
"uniffi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -316,6 +327,16 @@ version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "base64-simd"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195"
|
||||
dependencies = [
|
||||
"outref",
|
||||
"vsimd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.6.0"
|
||||
@@ -385,6 +406,15 @@ dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block2"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f"
|
||||
dependencies = [
|
||||
"objc2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "borsh"
|
||||
version = "1.5.3"
|
||||
@@ -970,7 +1000,7 @@ dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"rustversion",
|
||||
"windows",
|
||||
"windows 0.58.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1091,6 +1121,18 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "homedir"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5bdbbd5bc8c5749697ccaa352fa45aff8730cf21c68029c0eef1ffed7c3d6ba2"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"nix",
|
||||
"widestring",
|
||||
"windows 0.57.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.61"
|
||||
@@ -1541,6 +1583,18 @@ dependencies = [
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"cfg_aliases",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
@@ -1608,6 +1662,40 @@ dependencies = [
|
||||
"libm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc-sys"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310"
|
||||
|
||||
[[package]]
|
||||
name = "objc2"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804"
|
||||
dependencies = [
|
||||
"objc-sys",
|
||||
"objc2-encode",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-encode"
|
||||
version = "4.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8"
|
||||
|
||||
[[package]]
|
||||
name = "objc2-foundation"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"block2",
|
||||
"libc",
|
||||
"objc2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.7"
|
||||
@@ -1639,6 +1727,12 @@ dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "outref"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4030760ffd992bef45b0ae3f10ce1aba99e33464c90d14dd7c039884963ddc7a"
|
||||
|
||||
[[package]]
|
||||
name = "overload"
|
||||
version = "0.1.1"
|
||||
@@ -2968,6 +3062,12 @@ version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "vsimd"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.5.0"
|
||||
@@ -3072,6 +3172,12 @@ dependencies = [
|
||||
"wasite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "widestring"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
@@ -3103,6 +3209,16 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.57.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143"
|
||||
dependencies = [
|
||||
"windows-core 0.57.0",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.58.0"
|
||||
@@ -3122,19 +3238,42 @@ dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.57.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d"
|
||||
dependencies = [
|
||||
"windows-implement 0.57.0",
|
||||
"windows-interface 0.57.0",
|
||||
"windows-result 0.1.2",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.58.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-result",
|
||||
"windows-implement 0.58.0",
|
||||
"windows-interface 0.58.0",
|
||||
"windows-result 0.2.0",
|
||||
"windows-strings",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.57.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.58.0"
|
||||
@@ -3146,6 +3285,17 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.57.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.58.0"
|
||||
@@ -3157,6 +3307,15 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.2.0"
|
||||
@@ -3172,7 +3331,7 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
|
||||
dependencies = [
|
||||
"windows-result",
|
||||
"windows-result 0.2.0",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
|
||||
72
Cargo.toml
72
Cargo.toml
@@ -1,40 +1,48 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"./packages/backend/native",
|
||||
"./packages/common/native",
|
||||
"./packages/frontend/native",
|
||||
"./packages/frontend/native/sqlite_v1",
|
||||
"./packages/frontend/native/nbstore",
|
||||
"./packages/frontend/native/schema",
|
||||
"./packages/frontend/mobile-native",
|
||||
members = [
|
||||
"./packages/backend/native",
|
||||
"./packages/common/native",
|
||||
"./packages/frontend/mobile-native",
|
||||
"./packages/frontend/native",
|
||||
"./packages/frontend/native/nbstore",
|
||||
"./packages/frontend/native/schema",
|
||||
"./packages/frontend/native/sqlite_v1",
|
||||
]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.dependencies]
|
||||
affine_common = { path = "./packages/common/native" }
|
||||
criterion2 = { version = "2", default-features = false }
|
||||
anyhow = "1"
|
||||
chrono = "0.4"
|
||||
dotenvy = "0.15"
|
||||
file-format = { version = "0.26", features = ["reader"] }
|
||||
mimalloc = "0.1"
|
||||
napi = { version = "3.0.0-alpha.12", features = ["async", "chrono_date", "error_anyhow", "napi9", "serde"] }
|
||||
napi-build = { version = "2" }
|
||||
napi-derive = { version = "3.0.0-alpha.12" }
|
||||
notify = { version = "7", features = ["serde"] }
|
||||
once_cell = "1"
|
||||
parking_lot = "0.12"
|
||||
rand = "0.8"
|
||||
rayon = "1.10"
|
||||
serde = "1"
|
||||
serde_json = "1"
|
||||
sha3 = "0.10"
|
||||
sqlx = { version = "0.8", default-features = false, features = ["chrono", "macros", "migrate", "runtime-tokio", "sqlite", "tls-rustls"] }
|
||||
tiktoken-rs = "0.6"
|
||||
tokio = "1.37"
|
||||
uuid = "1.8"
|
||||
v_htmlescape = "0.15"
|
||||
y-octo = { git = "https://github.com/y-crdt/y-octo.git", branch = "main" }
|
||||
affine_common = { path = "./packages/common/native" }
|
||||
affine_nbstore = { path = "./packages/frontend/native/nbstore" }
|
||||
anyhow = "1"
|
||||
base64-simd = "0.8"
|
||||
chrono = "0.4"
|
||||
criterion2 = { version = "2", default-features = false }
|
||||
dashmap = "6"
|
||||
dotenvy = "0.15"
|
||||
file-format = { version = "0.26", features = ["reader"] }
|
||||
mimalloc = "0.1"
|
||||
napi = { version = "3.0.0-alpha.12", features = ["async", "chrono_date", "error_anyhow", "napi9", "serde"] }
|
||||
napi-build = { version = "2" }
|
||||
napi-derive = { version = "3.0.0-alpha.12" }
|
||||
notify = { version = "7", features = ["serde"] }
|
||||
objc2 = "0.5.2"
|
||||
objc2-foundation = "0.2.2"
|
||||
once_cell = "1"
|
||||
parking_lot = "0.12"
|
||||
homedir = "0.3"
|
||||
rand = "0.8"
|
||||
rayon = "1.10"
|
||||
serde = "1"
|
||||
serde_json = "1"
|
||||
sha3 = "0.10"
|
||||
sqlx = { version = "0.8", default-features = false, features = ["chrono", "macros", "migrate", "runtime-tokio", "sqlite", "tls-rustls"] }
|
||||
thiserror = "2"
|
||||
tiktoken-rs = "0.6"
|
||||
tokio = "1.37"
|
||||
uniffi = "0.28"
|
||||
uuid = "1.8"
|
||||
v_htmlescape = "0.15"
|
||||
y-octo = { git = "https://github.com/y-crdt/y-octo.git", branch = "main" }
|
||||
|
||||
[profile.dev.package.sqlx-macros]
|
||||
opt-level = 3
|
||||
|
||||
@@ -98,6 +98,7 @@ export function attachmentViewToggleMenu({
|
||||
button => button.type,
|
||||
({ type, label, action, disabled }) => html`
|
||||
<editor-menu-action
|
||||
aria-label=${label}
|
||||
data-testid=${`link-to-${type}`}
|
||||
?data-selected=${type === viewType}
|
||||
?disabled=${disabled}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import type { BlockCommands } from '@blocksuite/block-std';
|
||||
|
||||
import { insertBookmarkCommand } from './insert-bookmark.js';
|
||||
import { insertLinkByQuickSearchCommand } from './insert-link-by-quick-search.js';
|
||||
|
||||
export const commands: BlockCommands = {
|
||||
insertBookmark: insertBookmarkCommand,
|
||||
insertLinkByQuickSearch: insertLinkByQuickSearchCommand,
|
||||
};
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import type { InsertedLinkType } from '@blocksuite/affine-block-embed';
|
||||
import { QuickSearchProvider } from '@blocksuite/affine-shared/services';
|
||||
import type { Command } from '@blocksuite/block-std';
|
||||
|
||||
export type InsertedLinkType = {
|
||||
flavour?: 'affine:bookmark' | 'affine:embed-linked-doc';
|
||||
} | null;
|
||||
|
||||
export const insertLinkByQuickSearchCommand: Command<
|
||||
never,
|
||||
'insertedLinkType'
|
||||
@@ -34,7 +31,6 @@ export const insertLinkByQuickSearchCommand: Command<
|
||||
|
||||
// add normal link;
|
||||
if ('externalUrl' in result) {
|
||||
// @ts-expect-error FIXME: fix after bookmark refactor
|
||||
std.command.exec('insertBookmark', { url: result.externalUrl });
|
||||
return {
|
||||
flavour: 'affine:bookmark',
|
||||
@@ -2,6 +2,7 @@ import { BookmarkBlockComponent } from './bookmark-block';
|
||||
import { BookmarkEdgelessBlockComponent } from './bookmark-edgeless-block';
|
||||
import type { BookmarkBlockService } from './bookmark-service';
|
||||
import type { insertBookmarkCommand } from './commands/insert-bookmark';
|
||||
import type { insertLinkByQuickSearchCommand } from './commands/insert-link-by-quick-search';
|
||||
import { BookmarkCard } from './components/bookmark-card';
|
||||
|
||||
export function effects() {
|
||||
@@ -17,6 +18,7 @@ declare global {
|
||||
namespace BlockSuite {
|
||||
interface Commands {
|
||||
insertBookmark: typeof insertBookmarkCommand;
|
||||
insertLinkByQuickSearch: typeof insertLinkByQuickSearchCommand;
|
||||
}
|
||||
interface BlockServices {
|
||||
'affine:bookmark': BookmarkBlockService;
|
||||
|
||||
43
blocksuite/affine/block-edgeless-text/package.json
Normal file
43
blocksuite/affine/block-edgeless-text/package.json
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"name": "@blocksuite/affine-block-edgeless-text",
|
||||
"description": "Edgeless text block for BlockSuite.",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test:unit": "nx vite:test --run --passWithNoTests",
|
||||
"test:unit:coverage": "nx vite:test --run --coverage",
|
||||
"test:e2e": "playwright test"
|
||||
},
|
||||
"sideEffects": false,
|
||||
"keywords": [],
|
||||
"author": "toeverything",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@blocksuite/affine-block-surface": "workspace:*",
|
||||
"@blocksuite/affine-components": "workspace:*",
|
||||
"@blocksuite/affine-model": "workspace:*",
|
||||
"@blocksuite/affine-shared": "workspace:*",
|
||||
"@blocksuite/block-std": "workspace:*",
|
||||
"@blocksuite/global": "workspace:*",
|
||||
"@blocksuite/icons": "^2.1.75",
|
||||
"@blocksuite/inline": "workspace:*",
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@floating-ui/dom": "^1.6.10",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.1",
|
||||
"lit": "^3.2.0",
|
||||
"minimatch": "^10.0.1",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./effects": "./src/effects.ts"
|
||||
},
|
||||
"files": [
|
||||
"src",
|
||||
"dist",
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
]
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
import { EdgelessCRUDIdentifier } from '@blocksuite/affine-block-surface';
|
||||
import {
|
||||
EdgelessCRUDIdentifier,
|
||||
getSurfaceBlock,
|
||||
} from '@blocksuite/affine-block-surface';
|
||||
import { focusTextModel } from '@blocksuite/affine-components/rich-text';
|
||||
import type { Command } from '@blocksuite/block-std';
|
||||
import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx';
|
||||
import { Bound } from '@blocksuite/global/utils';
|
||||
|
||||
import { getSurfaceBlock } from '../../surface-ref-block/utils.js';
|
||||
import {
|
||||
EDGELESS_TEXT_BLOCK_MIN_HEIGHT,
|
||||
EDGELESS_TEXT_BLOCK_MIN_WIDTH,
|
||||
@@ -9,8 +9,6 @@ import { css, html } from 'lit';
|
||||
import { query, state } from 'lit/decorators.js';
|
||||
import { type StyleInfo, styleMap } from 'lit/directives/style-map.js';
|
||||
|
||||
import type { EdgelessRootService } from '../root-block/index.js';
|
||||
|
||||
export const EDGELESS_TEXT_BLOCK_MIN_WIDTH = 50;
|
||||
export const EDGELESS_TEXT_BLOCK_MIN_HEIGHT = 50;
|
||||
|
||||
@@ -43,10 +41,6 @@ export class EdgelessTextBlockComponent extends GfxBlockComponent<EdgelessTextBl
|
||||
this._updateH();
|
||||
});
|
||||
|
||||
get rootService() {
|
||||
return this.std.getService('affine:page') as EdgelessRootService;
|
||||
}
|
||||
|
||||
private _updateH() {
|
||||
const bound = Bound.deserialize(this.model.xywh);
|
||||
const rect = this._textContainer.getBoundingClientRect();
|
||||
@@ -92,35 +86,35 @@ export class EdgelessTextBlockComponent extends GfxBlockComponent<EdgelessTextBl
|
||||
this.model.propsUpdated.on(({ key }) => {
|
||||
this.updateComplete
|
||||
.then(() => {
|
||||
if (!this.host) return;
|
||||
|
||||
const command = this.host.command;
|
||||
const blockSelections = this.model.children.map(child =>
|
||||
this.host.selection.create('block', {
|
||||
blockId: child.id,
|
||||
})
|
||||
);
|
||||
const command = this.std.command;
|
||||
const blockSelections = this.model.children.map(
|
||||
child =>
|
||||
this.std.selection.create('block', {
|
||||
blockId: child.id,
|
||||
})
|
||||
// FIXME: BS-2216
|
||||
) as never;
|
||||
|
||||
if (key === 'fontStyle') {
|
||||
command.exec('formatBlock', {
|
||||
blockSelections,
|
||||
styles: {
|
||||
italic: null,
|
||||
},
|
||||
} as never,
|
||||
});
|
||||
} else if (key === 'color') {
|
||||
command.exec('formatBlock', {
|
||||
blockSelections,
|
||||
styles: {
|
||||
color: null,
|
||||
},
|
||||
} as never,
|
||||
});
|
||||
} else if (key === 'fontWeight') {
|
||||
command.exec('formatBlock', {
|
||||
blockSelections,
|
||||
styles: {
|
||||
bold: null,
|
||||
},
|
||||
} as never,
|
||||
});
|
||||
}
|
||||
})
|
||||
@@ -132,8 +126,8 @@ export class EdgelessTextBlockComponent extends GfxBlockComponent<EdgelessTextBl
|
||||
override firstUpdated(props: Map<string, unknown>) {
|
||||
super.firstUpdated(props);
|
||||
|
||||
const { disposables, rootService } = this;
|
||||
const edgelessSelection = rootService.selection;
|
||||
const { disposables, std } = this;
|
||||
const edgelessSelection = this.gfx.selection;
|
||||
|
||||
disposables.add(
|
||||
edgelessSelection.slots.updated.on(() => {
|
||||
@@ -185,8 +179,8 @@ export class EdgelessTextBlockComponent extends GfxBlockComponent<EdgelessTextBl
|
||||
}
|
||||
|
||||
if (newParagraphId) {
|
||||
this.rootService.selectionManager.setGroup('note', [
|
||||
this.rootService.selectionManager.create('text', {
|
||||
std.selection.setGroup('note', [
|
||||
std.selection.create('text', {
|
||||
from: {
|
||||
blockId: newParagraphId,
|
||||
index: 0,
|
||||
@@ -201,7 +195,7 @@ export class EdgelessTextBlockComponent extends GfxBlockComponent<EdgelessTextBl
|
||||
disposables.addFromEvent(this._textContainer, 'focusout', () => {
|
||||
if (!this._editing) return;
|
||||
|
||||
this.rootService.selectionManager.clear();
|
||||
this.std.selection.clear();
|
||||
});
|
||||
|
||||
let composingWidth = EDGELESS_TEXT_BLOCK_MIN_WIDTH;
|
||||
17
blocksuite/affine/block-edgeless-text/src/effects.ts
Normal file
17
blocksuite/affine/block-edgeless-text/src/effects.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import type { insertEdgelessTextCommand } from './commands/insert-edgeless-text';
|
||||
import { EdgelessTextBlockComponent } from './edgeless-text-block';
|
||||
|
||||
export function effects() {
|
||||
customElements.define('affine-edgeless-text', EdgelessTextBlockComponent);
|
||||
}
|
||||
|
||||
declare global {
|
||||
namespace BlockSuite {
|
||||
interface CommandContext {
|
||||
textId?: string;
|
||||
}
|
||||
interface Commands {
|
||||
insertEdgelessText: typeof insertEdgelessTextCommand;
|
||||
}
|
||||
}
|
||||
}
|
||||
35
blocksuite/affine/block-edgeless-text/tsconfig.json
Normal file
35
blocksuite/affine/block-edgeless-text/tsconfig.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src/",
|
||||
"outDir": "./dist/",
|
||||
"noEmit": false
|
||||
},
|
||||
"include": ["./src"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../framework/global"
|
||||
},
|
||||
{
|
||||
"path": "../../framework/store"
|
||||
},
|
||||
{
|
||||
"path": "../../framework/block-std"
|
||||
},
|
||||
{
|
||||
"path": "../../framework/inline"
|
||||
},
|
||||
{
|
||||
"path": "../model"
|
||||
},
|
||||
{
|
||||
"path": "../components"
|
||||
},
|
||||
{
|
||||
"path": "../shared"
|
||||
},
|
||||
{
|
||||
"path": "../block-surface"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { SurfaceBlockModel } from '@blocksuite/affine-block-surface';
|
||||
import { getSurfaceBlock } from '@blocksuite/affine-block-surface';
|
||||
import {
|
||||
type DocMode,
|
||||
type ImageBlockModel,
|
||||
@@ -23,6 +23,12 @@ import { render, type TemplateResult } from 'lit';
|
||||
import type { EmbedLinkedDocBlockComponent } from '../embed-linked-doc-block/index.js';
|
||||
import type { EmbedSyncedDocCard } from '../embed-synced-doc-block/components/embed-synced-doc-card.js';
|
||||
|
||||
// Throttle delay for block updates to reduce unnecessary re-renders
|
||||
// - Prevents rapid-fire updates when multiple blocks are updated in quick succession
|
||||
// - Ensures UI remains responsive while maintaining performance
|
||||
// - Small enough to feel instant to users, large enough to batch updates effectively
|
||||
export const RENDER_CARD_THROTTLE_MS = 60;
|
||||
|
||||
export function renderLinkedDocInCard(
|
||||
card: EmbedLinkedDocBlockComponent | EmbedSyncedDocCard
|
||||
) {
|
||||
@@ -257,11 +263,6 @@ export function isEmptyNote(note: BlockModel) {
|
||||
});
|
||||
}
|
||||
|
||||
function getSurfaceBlock(doc: Doc) {
|
||||
const blocks = doc.getBlocksByFlavour('affine:surface');
|
||||
return blocks.length !== 0 ? (blocks[0].model as SurfaceBlockModel) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the document content with a max length.
|
||||
*/
|
||||
|
||||
@@ -12,11 +12,10 @@ import { EmbedHtmlBlockComponent } from './embed-html-block';
|
||||
import { EmbedHtmlFullscreenToolbar } from './embed-html-block/components/fullscreen-toolbar';
|
||||
import { EmbedEdgelessHtmlBlockComponent } from './embed-html-block/embed-edgeless-html-block';
|
||||
import { EmbedLinkedDocBlockComponent } from './embed-linked-doc-block';
|
||||
import type { insertEmbedLinkedDocCommand } from './embed-linked-doc-block/commands/insert-embed-linked-doc';
|
||||
import type {
|
||||
InsertedLinkType,
|
||||
insertLinkByQuickSearchCommand,
|
||||
} from './embed-linked-doc-block/commands/insert-link-by-quick-search';
|
||||
insertEmbedLinkedDocCommand,
|
||||
} from './embed-linked-doc-block/commands/insert-embed-linked-doc';
|
||||
import { EmbedEdgelessLinkedDocBlockComponent } from './embed-linked-doc-block/embed-edgeless-linked-doc-block';
|
||||
import type { EmbedLinkedDocBlockConfig } from './embed-linked-doc-block/embed-linked-doc-config';
|
||||
import {
|
||||
@@ -121,15 +120,14 @@ declare global {
|
||||
'affine:embed-loom': EmbedLoomBlockService;
|
||||
'affine:embed-youtube': EmbedYoutubeBlockService;
|
||||
}
|
||||
interface BlockConfigs {
|
||||
'affine:embed-linked-doc': EmbedLinkedDocBlockConfig;
|
||||
}
|
||||
interface CommandContext {
|
||||
insertedLinkType?: Promise<InsertedLinkType>;
|
||||
}
|
||||
interface BlockConfigs {
|
||||
'affine:embed-linked-doc': EmbedLinkedDocBlockConfig;
|
||||
}
|
||||
interface Commands {
|
||||
insertEmbedLinkedDoc: typeof insertEmbedLinkedDocCommand;
|
||||
insertLinkByQuickSearch: typeof insertLinkByQuickSearchCommand;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { BlockCommands } from '@blocksuite/block-std';
|
||||
|
||||
import { insertEmbedLinkedDocCommand } from './insert-embed-linked-doc.js';
|
||||
import { insertLinkByQuickSearchCommand } from './insert-link-by-quick-search.js';
|
||||
|
||||
export const commands: BlockCommands = {
|
||||
insertEmbedLinkedDoc: insertEmbedLinkedDocCommand,
|
||||
insertLinkByQuickSearch: insertLinkByQuickSearchCommand,
|
||||
};
|
||||
|
||||
export type { InsertedLinkType } from './insert-embed-linked-doc';
|
||||
|
||||
@@ -3,6 +3,10 @@ import type { Command } from '@blocksuite/block-std';
|
||||
|
||||
import { insertEmbedCard } from '../../common/insert-embed-card.js';
|
||||
|
||||
export type InsertedLinkType = {
|
||||
flavour?: 'affine:bookmark' | 'affine:embed-linked-doc';
|
||||
} | null;
|
||||
|
||||
export const insertEmbedLinkedDocCommand: Command<
|
||||
never,
|
||||
'insertedLinkType',
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
matchFlavours,
|
||||
referenceToNode,
|
||||
} from '@blocksuite/affine-shared/utils';
|
||||
import { Bound } from '@blocksuite/global/utils';
|
||||
import { Bound, throttle } from '@blocksuite/global/utils';
|
||||
import { DocCollection } from '@blocksuite/store';
|
||||
import { computed } from '@preact/signals-core';
|
||||
import { html, nothing } from 'lit';
|
||||
@@ -33,7 +33,10 @@ import { styleMap } from 'lit/directives/style-map.js';
|
||||
import { when } from 'lit/directives/when.js';
|
||||
|
||||
import { EmbedBlockComponent } from '../common/embed-block-element.js';
|
||||
import { renderLinkedDocInCard } from '../common/render-linked-doc.js';
|
||||
import {
|
||||
RENDER_CARD_THROTTLE_MS,
|
||||
renderLinkedDocInCard,
|
||||
} from '../common/render-linked-doc.js';
|
||||
import { SyncedDocErrorIcon } from '../embed-synced-doc-block/styles.js';
|
||||
import {
|
||||
type EmbedLinkedDocBlockConfig,
|
||||
@@ -301,24 +304,28 @@ export class EmbedLinkedDocBlockComponent extends EmbedBlockComponent<EmbedLinke
|
||||
});
|
||||
})
|
||||
);
|
||||
// Should throttle the blockUpdated event to avoid too many re-renders
|
||||
// Because the blockUpdated event is triggered too frequently at some cases
|
||||
this.disposables.add(
|
||||
linkedDoc.slots.blockUpdated.on(payload => {
|
||||
if (
|
||||
payload.type === 'update' &&
|
||||
['', 'caption', 'xywh'].includes(payload.props.key)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
linkedDoc.slots.blockUpdated.on(
|
||||
throttle(payload => {
|
||||
if (
|
||||
payload.type === 'update' &&
|
||||
['', 'caption', 'xywh'].includes(payload.props.key)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (payload.type === 'add' && payload.init) {
|
||||
return;
|
||||
}
|
||||
if (payload.type === 'add' && payload.init) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._load().catch(e => {
|
||||
console.error(e);
|
||||
this.isError = true;
|
||||
});
|
||||
})
|
||||
this._load().catch(e => {
|
||||
console.error(e);
|
||||
this.isError = true;
|
||||
});
|
||||
}, RENDER_CARD_THROTTLE_MS)
|
||||
)
|
||||
);
|
||||
|
||||
this._setDocUpdatedAt();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export * from './adapters/index.js';
|
||||
export * from './embed-linked-doc-block.js';
|
||||
export * from './embed-linked-doc-config.js';
|
||||
export * from './embed-linked-doc-spec.js';
|
||||
export * from './adapters';
|
||||
export type { InsertedLinkType } from './commands';
|
||||
export * from './embed-linked-doc-block';
|
||||
export * from './embed-linked-doc-config';
|
||||
export * from './embed-linked-doc-spec';
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import { ThemeProvider } from '@blocksuite/affine-shared/services';
|
||||
import { isGfxBlockComponent, ShadowlessElement } from '@blocksuite/block-std';
|
||||
import { WithDisposable } from '@blocksuite/global/utils';
|
||||
import { throttle, WithDisposable } from '@blocksuite/global/utils';
|
||||
import { html, nothing } from 'lit';
|
||||
import { property, queryAsync } from 'lit/decorators.js';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
|
||||
import { renderLinkedDocInCard } from '../../common/render-linked-doc.js';
|
||||
import {
|
||||
RENDER_CARD_THROTTLE_MS,
|
||||
renderLinkedDocInCard,
|
||||
} from '../../common/render-linked-doc.js';
|
||||
import type { EmbedSyncedDocBlockComponent } from '../embed-synced-doc-block.js';
|
||||
import { cardStyles } from '../styles.js';
|
||||
import { getSyncedDocIcons } from '../utils.js';
|
||||
@@ -101,19 +104,23 @@ export class EmbedSyncedDocCard extends WithDisposable(ShadowlessElement) {
|
||||
renderLinkedDocInCard(this);
|
||||
})
|
||||
);
|
||||
// Should throttle the blockUpdated event to avoid too many re-renders
|
||||
// Because the blockUpdated event is triggered too frequently at some cases
|
||||
this.disposables.add(
|
||||
syncedDoc.slots.blockUpdated.on(payload => {
|
||||
if (this._dragging) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
payload.type === 'update' &&
|
||||
['', 'caption', 'xywh'].includes(payload.props.key)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
renderLinkedDocInCard(this);
|
||||
})
|
||||
syncedDoc.slots.blockUpdated.on(
|
||||
throttle(payload => {
|
||||
if (this._dragging) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
payload.type === 'update' &&
|
||||
['', 'caption', 'xywh'].includes(payload.props.key)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
renderLinkedDocInCard(this);
|
||||
}, RENDER_CARD_THROTTLE_MS)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ import {
|
||||
tryMoveNode,
|
||||
} from './utils/mindmap/utils';
|
||||
export * from './extensions';
|
||||
export { getLastPropsKey } from './utils/get-last-props-key';
|
||||
export { getLastPropsKey, getSurfaceBlock } from './utils';
|
||||
export type { Options } from './utils/rough/core';
|
||||
export { sortIndex } from './utils/sort';
|
||||
export { updateXYWH } from './utils/update-xywh.js';
|
||||
|
||||
@@ -2,6 +2,7 @@ import { BlockService } from '@blocksuite/block-std';
|
||||
import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx';
|
||||
|
||||
import { type SurfaceBlockModel, SurfaceBlockSchema } from './surface-model.js';
|
||||
import { getSurfaceBlock } from './utils/get-surface-block.js';
|
||||
|
||||
export class SurfaceBlockService extends BlockService {
|
||||
static override readonly flavour = SurfaceBlockSchema.model.flavour;
|
||||
@@ -15,9 +16,10 @@ export class SurfaceBlockService extends BlockService {
|
||||
override mounted(): void {
|
||||
super.mounted();
|
||||
|
||||
this.surface = this.doc.getBlockByFlavour(
|
||||
'affine:surface'
|
||||
)[0] as SurfaceBlockModel;
|
||||
const surface = getSurfaceBlock(this.doc);
|
||||
|
||||
// FIXME: BS-2271
|
||||
this.surface = surface!;
|
||||
|
||||
if (!this.surface) {
|
||||
const disposable = this.doc.slots.blockUpdated.on(payload => {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import type { Doc } from '@blocksuite/store';
|
||||
|
||||
import type { SurfaceBlockModel } from '../surface-model';
|
||||
|
||||
export function getSurfaceBlock(doc: Doc) {
|
||||
const blocks = doc.getBlocksByFlavour('affine:surface');
|
||||
return blocks.length !== 0 ? (blocks[0].model as SurfaceBlockModel) : null;
|
||||
}
|
||||
@@ -34,3 +34,4 @@ export function normalizeWheelDeltaY(delta: number, zoom = 1) {
|
||||
}
|
||||
|
||||
export { getLastPropsKey } from './get-last-props-key';
|
||||
export { getSurfaceBlock } from './get-surface-block';
|
||||
|
||||
@@ -56,7 +56,7 @@ export class FileDropExtension extends LifeCycleWatcher {
|
||||
FileDropExtension.indicator.rect = null;
|
||||
};
|
||||
|
||||
onDragOver = (event: DragEvent) => {
|
||||
onDragMove = (event: DragEvent) => {
|
||||
event.preventDefault();
|
||||
|
||||
const dataTransfer = event.dataTransfer;
|
||||
@@ -149,9 +149,22 @@ export class FileDropExtension extends LifeCycleWatcher {
|
||||
const droppedFiles = dataTransfer.files;
|
||||
if (!droppedFiles || !droppedFiles.length) return;
|
||||
|
||||
const { targetModel, type: place } = this;
|
||||
const { x, y } = event;
|
||||
const { clientX, clientY } = event;
|
||||
const point = new Point(clientX, clientY);
|
||||
const element = getClosestBlockComponentByPoint(point.clone());
|
||||
|
||||
let result: DropResult | null = null;
|
||||
if (element) {
|
||||
const model = element.model;
|
||||
const parent = this.std.doc.getParent(model);
|
||||
if (!matchFlavours(parent, ['affine:surface' as BlockSuite.Flavour])) {
|
||||
result = calcDropTarget(point, model, element);
|
||||
}
|
||||
}
|
||||
FileDropExtension.dropResult = result;
|
||||
|
||||
const { x, y } = event;
|
||||
const { targetModel, type: place } = this;
|
||||
const drop = onDrop({
|
||||
std: this.std,
|
||||
files: [...droppedFiles],
|
||||
@@ -170,21 +183,34 @@ export class FileDropExtension extends LifeCycleWatcher {
|
||||
super.mounted();
|
||||
const std = this.std;
|
||||
|
||||
std.event.add('nativeDragOver', context => {
|
||||
const event = context.get('dndState');
|
||||
this.onDragOver(event.raw);
|
||||
});
|
||||
std.event.add('nativeDragLeave', () => {
|
||||
this.onDragLeave();
|
||||
});
|
||||
std.provider.getAll(FileDropConfigExtensionIdentifier).forEach(options => {
|
||||
if (options.onDrop) {
|
||||
std.event.add('nativeDrop', context => {
|
||||
const event = context.get('dndState');
|
||||
return this._onDrop(event.raw, options);
|
||||
});
|
||||
}
|
||||
});
|
||||
std.event.disposables.add(
|
||||
std.event.add('nativeDragMove', context => {
|
||||
const event = context.get('dndState');
|
||||
this.onDragMove(event.raw);
|
||||
})
|
||||
);
|
||||
std.event.disposables.add(
|
||||
std.event.add('nativeDragLeave', () => {
|
||||
this.onDragLeave();
|
||||
})
|
||||
);
|
||||
std.event.disposables.add(
|
||||
std.event.add('nativeDrop', context => {
|
||||
const values = std.provider
|
||||
.getAll(FileDropConfigExtensionIdentifier)
|
||||
.values();
|
||||
|
||||
for (const value of values) {
|
||||
if (value.onDrop) {
|
||||
const event = context.get('dndState');
|
||||
const drop = this._onDrop(event.raw, value);
|
||||
if (drop) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { AdapterFactoryIdentifier } from '@blocksuite/affine-shared/adapters';
|
||||
import type { ExtensionType } from '@blocksuite/block-std';
|
||||
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
|
||||
import { sha } from '@blocksuite/global/utils';
|
||||
@@ -20,6 +19,8 @@ import {
|
||||
type ToDocSnapshotPayload,
|
||||
} from '@blocksuite/store';
|
||||
|
||||
import { AdapterFactoryIdentifier } from './types/adapter';
|
||||
|
||||
export type Attachment = File[];
|
||||
|
||||
type AttachmentToSliceSnapshotPayload = {
|
||||
@@ -1,4 +1,3 @@
|
||||
import { AdapterFactoryIdentifier } from '@blocksuite/affine-shared/adapters';
|
||||
import type { ExtensionType } from '@blocksuite/block-std';
|
||||
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
|
||||
import { sha } from '@blocksuite/global/utils';
|
||||
@@ -20,6 +19,8 @@ import {
|
||||
type ToDocSnapshotPayload,
|
||||
} from '@blocksuite/store';
|
||||
|
||||
import { AdapterFactoryIdentifier } from './types/adapter';
|
||||
|
||||
export type Image = File[];
|
||||
|
||||
type ImageToSliceSnapshotPayload = {
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './attachment';
|
||||
export {
|
||||
BlockHtmlAdapterExtension,
|
||||
type BlockHtmlAdapterMatcher,
|
||||
@@ -14,6 +15,7 @@ export {
|
||||
type InlineDeltaToHtmlAdapterMatcher,
|
||||
InlineDeltaToHtmlAdapterMatcherIdentifier,
|
||||
} from './html';
|
||||
export * from './image';
|
||||
export {
|
||||
BlockMarkdownAdapterExtension,
|
||||
type BlockMarkdownAdapterMatcher,
|
||||
@@ -33,11 +35,15 @@ export {
|
||||
BlockNotionHtmlAdapterMatcherIdentifier,
|
||||
type InlineDeltaToNotionHtmlAdapterMatcher,
|
||||
type NotionHtml,
|
||||
NotionHtmlAdapter,
|
||||
NotionHtmlAdapterFactoryExtension,
|
||||
NotionHtmlAdapterFactoryIdentifier,
|
||||
NotionHtmlASTToDeltaExtension,
|
||||
type NotionHtmlASTToDeltaMatcher,
|
||||
NotionHtmlASTToDeltaMatcherIdentifier,
|
||||
NotionHtmlDeltaConverter,
|
||||
} from './notion-html';
|
||||
export * from './notion-text';
|
||||
export {
|
||||
BlockPlainTextAdapterExtension,
|
||||
type BlockPlainTextAdapterMatcher,
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export * from './block-adapter.js';
|
||||
export * from './delta-converter.js';
|
||||
export * from './type.js';
|
||||
export * from './notion-html.js';
|
||||
|
||||
@@ -2,17 +2,6 @@ import {
|
||||
DEFAULT_NOTE_BACKGROUND_COLOR,
|
||||
NoteDisplayMode,
|
||||
} from '@blocksuite/affine-model';
|
||||
import {
|
||||
type AdapterContext,
|
||||
AdapterFactoryIdentifier,
|
||||
type BlockNotionHtmlAdapterMatcher,
|
||||
BlockNotionHtmlAdapterMatcherIdentifier,
|
||||
HastUtils,
|
||||
type HtmlAST,
|
||||
type NotionHtml,
|
||||
NotionHtmlASTToDeltaMatcherIdentifier,
|
||||
NotionHtmlDeltaConverter,
|
||||
} from '@blocksuite/affine-shared/adapters';
|
||||
import type { ExtensionType } from '@blocksuite/block-std';
|
||||
import type { ServiceProvider } from '@blocksuite/global/di';
|
||||
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
|
||||
@@ -35,6 +24,23 @@ import {
|
||||
import rehypeParse from 'rehype-parse';
|
||||
import { unified } from 'unified';
|
||||
|
||||
import {
|
||||
type AdapterContext,
|
||||
AdapterFactoryIdentifier,
|
||||
} from '../types/adapter';
|
||||
import type { HtmlAST } from '../types/hast';
|
||||
import { HastUtils } from '../utils/hast';
|
||||
import {
|
||||
type BlockNotionHtmlAdapterMatcher,
|
||||
BlockNotionHtmlAdapterMatcherIdentifier,
|
||||
} from './block-adapter';
|
||||
import {
|
||||
NotionHtmlASTToDeltaMatcherIdentifier,
|
||||
NotionHtmlDeltaConverter,
|
||||
} from './delta-converter';
|
||||
|
||||
export type NotionHtml = string;
|
||||
|
||||
type NotionHtmlToSliceSnapshotPayload = {
|
||||
file: NotionHtml;
|
||||
assets?: AssetsManager;
|
||||
@@ -1 +0,0 @@
|
||||
export type NotionHtml = string;
|
||||
@@ -1,6 +1,4 @@
|
||||
import { DEFAULT_NOTE_BACKGROUND_COLOR } from '@blocksuite/affine-model';
|
||||
import { AdapterFactoryIdentifier } from '@blocksuite/affine-shared/adapters';
|
||||
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
|
||||
import type { ExtensionType } from '@blocksuite/block-std';
|
||||
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
|
||||
import type { DeltaInsert } from '@blocksuite/inline';
|
||||
@@ -17,6 +15,9 @@ import {
|
||||
type SliceSnapshot,
|
||||
} from '@blocksuite/store';
|
||||
|
||||
import type { AffineTextAttributes } from '../types';
|
||||
import { AdapterFactoryIdentifier } from './types/adapter';
|
||||
|
||||
type NotionEditingStyle = {
|
||||
0: string;
|
||||
};
|
||||
@@ -16,6 +16,7 @@
|
||||
"dependencies": {
|
||||
"@blocksuite/affine-block-attachment": "workspace:*",
|
||||
"@blocksuite/affine-block-bookmark": "workspace:*",
|
||||
"@blocksuite/affine-block-edgeless-text": "workspace:*",
|
||||
"@blocksuite/affine-block-embed": "workspace:*",
|
||||
"@blocksuite/affine-block-frame": "workspace:*",
|
||||
"@blocksuite/affine-block-image": "workspace:*",
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
DEFAULT_NOTE_BACKGROUND_COLOR,
|
||||
NoteDisplayMode,
|
||||
} from '@blocksuite/affine-model';
|
||||
import { NotionHtmlAdapter } from '@blocksuite/affine-shared/adapters';
|
||||
import { Container } from '@blocksuite/global/di';
|
||||
import {
|
||||
AssetsManager,
|
||||
@@ -12,7 +13,6 @@ import { describe, expect, test } from 'vitest';
|
||||
|
||||
import { defaultBlockNotionHtmlAdapterMatchers } from '../../_common/adapters/notion-html/block-matcher.js';
|
||||
import { notionHtmlInlineToDeltaMatchers } from '../../_common/adapters/notion-html/delta-converter/html-inline.js';
|
||||
import { NotionHtmlAdapter } from '../../_common/adapters/notion-html/notion-html.js';
|
||||
import { nanoidReplacement } from '../../_common/test-utils/test-utils.js';
|
||||
import { createJob } from '../utils/create-job.js';
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { DEFAULT_NOTE_BACKGROUND_COLOR } from '@blocksuite/affine-model';
|
||||
import { NotionTextAdapter } from '@blocksuite/affine-shared/adapters';
|
||||
import type { SliceSnapshot } from '@blocksuite/store';
|
||||
import { describe, expect, test } from 'vitest';
|
||||
|
||||
import { NotionTextAdapter } from '../../_common/adapters/notion-text.js';
|
||||
import { nanoidReplacement } from '../../_common/test-utils/test-utils.js';
|
||||
import { createJob } from '../utils/create-job.js';
|
||||
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import {
|
||||
AttachmentAdapterFactoryExtension,
|
||||
HtmlAdapterFactoryExtension,
|
||||
ImageAdapterFactoryExtension,
|
||||
NotionHtmlAdapterFactoryExtension,
|
||||
NotionTextAdapterFactoryExtension,
|
||||
PlainTextAdapterFactoryExtension,
|
||||
} from '@blocksuite/affine-shared/adapters';
|
||||
import type { ExtensionType } from '@blocksuite/block-std';
|
||||
|
||||
import { AttachmentAdapterFactoryExtension } from './attachment.js';
|
||||
import { htmlInlineToDeltaMatchers } from './html/delta-converter/html-inline.js';
|
||||
import { inlineDeltaToHtmlAdapterMatchers } from './html/delta-converter/inline-delta.js';
|
||||
import { ImageAdapterFactoryExtension } from './image.js';
|
||||
import { MarkdownAdapterFactoryExtension } from './markdown/markdown.js';
|
||||
import { MixTextAdapterFactoryExtension } from './mix-text.js';
|
||||
import { notionHtmlInlineToDeltaMatchers } from './notion-html/delta-converter/html-inline.js';
|
||||
import { NotionHtmlAdapterFactoryExtension } from './notion-html/notion-html.js';
|
||||
import { NotionTextAdapterFactoryExtension } from './notion-text.js';
|
||||
import { inlineDeltaToPlainTextAdapterMatchers } from './plain-text/delta-converter/inline-delta.js';
|
||||
|
||||
export const AdapterFactoryExtensions: ExtensionType[] = [
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
export * from './attachment.js';
|
||||
export * from './extension.js';
|
||||
export * from './image.js';
|
||||
export * from './markdown/index.js';
|
||||
export * from './mix-text.js';
|
||||
export * from './notion-html/index.js';
|
||||
export * from './notion-text.js';
|
||||
|
||||
@@ -1,6 +1,2 @@
|
||||
export { defaultBlockNotionHtmlAdapterMatchers } from './block-matcher.js';
|
||||
export {
|
||||
NotionHtmlAdapter,
|
||||
NotionHtmlAdapterFactoryExtension,
|
||||
NotionHtmlAdapterFactoryIdentifier,
|
||||
} from './notion-html.js';
|
||||
export { notionHtmlInlineToDeltaMatchers } from './delta-converter/html-inline.js';
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { NotionHtmlAdapter } from '@blocksuite/affine-shared/adapters';
|
||||
import { Container } from '@blocksuite/global/di';
|
||||
import { sha } from '@blocksuite/global/utils';
|
||||
import { type DocCollection, extMimeMap, Job } from '@blocksuite/store';
|
||||
|
||||
import { defaultBlockNotionHtmlAdapterMatchers } from '../adapters/notion-html/block-matcher.js';
|
||||
import { notionHtmlInlineToDeltaMatchers } from '../adapters/notion-html/delta-converter/html-inline.js';
|
||||
import { NotionHtmlAdapter } from '../adapters/notion-html/notion-html.js';
|
||||
import { defaultImageProxyMiddleware } from './middlewares.js';
|
||||
import { Unzip } from './utils.js';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { getSurfaceBlock } from '@blocksuite/affine-block-surface';
|
||||
import type { FrameBlockModel, NoteBlockModel } from '@blocksuite/affine-model';
|
||||
import { NoteDisplayMode } from '@blocksuite/affine-model';
|
||||
import { DocModeProvider } from '@blocksuite/affine-shared/services';
|
||||
@@ -15,7 +16,6 @@ import {
|
||||
isFrameBlock,
|
||||
isNoteBlock,
|
||||
} from '../../root-block/edgeless/utils/query.js';
|
||||
import { getSurfaceBlock } from '../../surface-ref-block/utils.js';
|
||||
|
||||
export function addBlocksToDoc(
|
||||
targetDoc: Doc,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { EdgelessTextBlockSpec } from '@blocksuite/affine-block-edgeless-text';
|
||||
import { FrameBlockSpec } from '@blocksuite/affine-block-frame';
|
||||
import { LatexBlockSpec } from '@blocksuite/affine-block-latex';
|
||||
import { EdgelessSurfaceBlockSpec } from '@blocksuite/affine-block-surface';
|
||||
|
||||
import { EdgelessTextBlockSpec } from '../../edgeless-text-block/index.js';
|
||||
import { EdgelessRootBlockSpec } from '../../root-block/edgeless/edgeless-root-spec.js';
|
||||
import { EdgelessSurfaceRefBlockSpec } from '../../surface-ref-block/surface-ref-spec.js';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { EdgelessTextBlockSpec } from '@blocksuite/affine-block-edgeless-text';
|
||||
import { FrameBlockSpec } from '@blocksuite/affine-block-frame';
|
||||
import { LatexBlockSpec } from '@blocksuite/affine-block-latex';
|
||||
import {
|
||||
@@ -7,7 +8,6 @@ import {
|
||||
import { FontLoaderService } from '@blocksuite/affine-shared/services';
|
||||
import type { ExtensionType } from '@blocksuite/block-std';
|
||||
|
||||
import { EdgelessTextBlockSpec } from '../../edgeless-text-block/edgeless-text-spec.js';
|
||||
import { EdgelessRootBlockSpec } from '../../root-block/edgeless/edgeless-root-spec.js';
|
||||
import {
|
||||
EdgelessFrameManager,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { EdgelessTextBlockSpec } from '@blocksuite/affine-block-edgeless-text';
|
||||
import { FrameBlockSpec } from '@blocksuite/affine-block-frame';
|
||||
import { LatexBlockSpec } from '@blocksuite/affine-block-latex';
|
||||
import {
|
||||
@@ -19,7 +20,6 @@ import {
|
||||
} from '@blocksuite/block-std';
|
||||
import { literal } from 'lit/static-html.js';
|
||||
|
||||
import { EdgelessTextBlockSpec } from '../../edgeless-text-block/index.js';
|
||||
import { PreviewEdgelessRootBlockSpec } from '../../root-block/edgeless/edgeless-root-spec.js';
|
||||
import { PageRootService } from '../../root-block/page/page-root-service.js';
|
||||
import {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { effects as blockAttachmentEffects } from '@blocksuite/affine-block-attachment/effects';
|
||||
import { effects as blockBookmarkEffects } from '@blocksuite/affine-block-bookmark/effects';
|
||||
import { effects as blockEdgelessTextEffects } from '@blocksuite/affine-block-edgeless-text/effects';
|
||||
import { effects as blockEmbedEffects } from '@blocksuite/affine-block-embed/effects';
|
||||
import { effects as blockFrameEffects } from '@blocksuite/affine-block-frame/effects';
|
||||
import { effects as blockImageEffects } from '@blocksuite/affine-block-image/effects';
|
||||
@@ -64,8 +65,6 @@ import {
|
||||
HeaderAreaTextCellEditing,
|
||||
} from './database-block/properties/title/text.js';
|
||||
import { DividerBlockComponent } from './divider-block/index.js';
|
||||
import type { insertEdgelessTextCommand } from './edgeless-text-block/commands/insert-edgeless-text.js';
|
||||
import { EdgelessTextBlockComponent } from './edgeless-text-block/index.js';
|
||||
import { EdgelessAutoCompletePanel } from './root-block/edgeless/components/auto-complete/auto-complete-panel.js';
|
||||
import { EdgelessAutoComplete } from './root-block/edgeless/components/auto-complete/edgeless-auto-complete.js';
|
||||
import { EdgelessToolIconButton } from './root-block/edgeless/components/buttons/tool-icon-button.js';
|
||||
@@ -260,6 +259,7 @@ export function effects() {
|
||||
blockDatabaseEffects();
|
||||
blockSurfaceRefEffects();
|
||||
blockLatexEffects();
|
||||
blockEdgelessTextEffects();
|
||||
|
||||
componentCaptionEffects();
|
||||
componentContextMenuEffects();
|
||||
@@ -293,7 +293,6 @@ export function effects() {
|
||||
'affine-database-rich-text-cell-editing',
|
||||
RichTextCellEditing
|
||||
);
|
||||
customElements.define('affine-edgeless-text', EdgelessTextBlockComponent);
|
||||
customElements.define('center-peek', CenterPeek);
|
||||
customElements.define('database-datasource-note-renderer', NoteRenderer);
|
||||
customElements.define('database-datasource-block-renderer', BlockRenderer);
|
||||
@@ -528,14 +527,10 @@ export function effects() {
|
||||
|
||||
declare global {
|
||||
namespace BlockSuite {
|
||||
interface Commands {
|
||||
insertEdgelessText: typeof insertEdgelessTextCommand;
|
||||
}
|
||||
interface CommandContext {
|
||||
focusBlock?: BlockComponent | null;
|
||||
anchorBlock?: BlockComponent | null;
|
||||
updatedBlocks?: BlockModel[];
|
||||
textId?: string;
|
||||
}
|
||||
interface BlockConfigs {
|
||||
'affine:code': CodeBlockConfig;
|
||||
|
||||
@@ -20,7 +20,6 @@ export * from './code-block/index.js';
|
||||
export * from './data-view-block/index.js';
|
||||
export * from './database-block/index.js';
|
||||
export * from './divider-block/index.js';
|
||||
export * from './edgeless-text-block/index.js';
|
||||
export { EdgelessTemplatePanel } from './root-block/edgeless/components/toolbar/template/template-panel.js';
|
||||
export type {
|
||||
Template,
|
||||
@@ -46,6 +45,7 @@ export {
|
||||
export * from './surface-ref-block/index.js';
|
||||
export * from '@blocksuite/affine-block-attachment';
|
||||
export * from '@blocksuite/affine-block-bookmark';
|
||||
export * from '@blocksuite/affine-block-edgeless-text';
|
||||
export * from '@blocksuite/affine-block-embed';
|
||||
export * from '@blocksuite/affine-block-frame';
|
||||
export * from '@blocksuite/affine-block-image';
|
||||
@@ -100,9 +100,18 @@ export {
|
||||
} from '@blocksuite/affine-components/toolbar';
|
||||
export * from '@blocksuite/affine-model';
|
||||
export {
|
||||
AttachmentAdapter,
|
||||
AttachmentAdapterFactoryExtension,
|
||||
AttachmentAdapterFactoryIdentifier,
|
||||
HtmlAdapter,
|
||||
HtmlAdapterFactoryExtension,
|
||||
HtmlAdapterFactoryIdentifier,
|
||||
ImageAdapter,
|
||||
ImageAdapterFactoryExtension,
|
||||
ImageAdapterFactoryIdentifier,
|
||||
NotionTextAdapter,
|
||||
NotionTextAdapterFactoryExtension,
|
||||
NotionTextAdapterFactoryIdentifier,
|
||||
PlainTextAdapter,
|
||||
PlainTextAdapterFactoryExtension,
|
||||
PlainTextAdapterFactoryIdentifier,
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { HtmlAdapter } from '@blocksuite/affine-shared/adapters';
|
||||
import {
|
||||
AttachmentAdapter,
|
||||
HtmlAdapter,
|
||||
ImageAdapter,
|
||||
NotionTextAdapter,
|
||||
} from '@blocksuite/affine-shared/adapters';
|
||||
import type { BlockComponent, UIEventHandler } from '@blocksuite/block-std';
|
||||
import { DisposableGroup } from '@blocksuite/global/utils';
|
||||
import type { BlockSnapshot, Doc } from '@blocksuite/store';
|
||||
|
||||
import {
|
||||
AttachmentAdapter,
|
||||
ImageAdapter,
|
||||
MixTextAdapter,
|
||||
NotionTextAdapter,
|
||||
} from '../../_common/adapters/index.js';
|
||||
import { MixTextAdapter } from '../../_common/adapters/index.js';
|
||||
import {
|
||||
defaultImageProxyMiddleware,
|
||||
replaceIdMiddleware,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { EdgelessTextBlockComponent } from '@blocksuite/affine-block-edgeless-text';
|
||||
import { EDGELESS_TEXT_BLOCK_MIN_WIDTH } from '@blocksuite/affine-block-edgeless-text';
|
||||
import {
|
||||
EMBED_HTML_MIN_HEIGHT,
|
||||
EMBED_HTML_MIN_WIDTH,
|
||||
@@ -59,8 +61,6 @@ import { ifDefined } from 'lit/directives/if-defined.js';
|
||||
import { styleMap } from 'lit/directives/style-map.js';
|
||||
|
||||
import { isMindmapNode } from '../../../../_common/edgeless/mindmap/index.js';
|
||||
import type { EdgelessTextBlockComponent } from '../../../../edgeless-text-block/edgeless-text-block.js';
|
||||
import { EDGELESS_TEXT_BLOCK_MIN_WIDTH } from '../../../../edgeless-text-block/edgeless-text-block.js';
|
||||
import type { EdgelessRootBlockComponent } from '../../edgeless-root-block.js';
|
||||
import type {
|
||||
EdgelessFrameManager,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { EdgelessTextBlockComponent } from '@blocksuite/affine-block-edgeless-text';
|
||||
import {
|
||||
ConnectorElementModel,
|
||||
ConnectorMode,
|
||||
@@ -27,7 +28,6 @@ import {
|
||||
isSingleMindMapNode,
|
||||
} from '../../_common/edgeless/mindmap/index.js';
|
||||
import { LassoMode } from '../../_common/types.js';
|
||||
import { EdgelessTextBlockComponent } from '../../edgeless-text-block/edgeless-text-block.js';
|
||||
import { PageKeyboardManager } from '../keyboard/keyboard-manager.js';
|
||||
import { GfxBlockModel } from './block-model.js';
|
||||
import type { EdgelessRootBlockComponent } from './edgeless-root-block.js';
|
||||
@@ -436,13 +436,15 @@ export class EdgelessPageKeyboardManager extends PageKeyboardManager {
|
||||
'keyDown',
|
||||
ctx => {
|
||||
const event = ctx.get('keyboardState').raw;
|
||||
const service = this.rootComponent.service;
|
||||
const selection = service.selection;
|
||||
const gfx = this.rootComponent.gfx;
|
||||
const selection = gfx.selection;
|
||||
|
||||
if (event.code === 'Space' && !event.repeat) {
|
||||
this._space(event);
|
||||
} else if (
|
||||
!selection.editing &&
|
||||
event.key.length === 1 &&
|
||||
// the key might be `Unidentified` according to mdn
|
||||
event.key?.length === 1 &&
|
||||
!event.shiftKey &&
|
||||
!event.ctrlKey &&
|
||||
!event.altKey &&
|
||||
@@ -452,7 +454,7 @@ export class EdgelessPageKeyboardManager extends PageKeyboardManager {
|
||||
const doc = this.rootComponent.doc;
|
||||
|
||||
if (isSingleMindMapNode(elements)) {
|
||||
const target = service.getElementById(
|
||||
const target = gfx.getElementById(
|
||||
elements[0].id
|
||||
) as ShapeElementModel;
|
||||
if (target.text) {
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
EdgelessLegacySlotIdentifier,
|
||||
type ElementRenderer,
|
||||
elementRenderers,
|
||||
getSurfaceBlock,
|
||||
type SurfaceBlockModel,
|
||||
type SurfaceContext,
|
||||
} from '@blocksuite/affine-block-surface';
|
||||
@@ -30,7 +31,6 @@ import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
|
||||
import { Bound, getCommonBound } from '@blocksuite/global/utils';
|
||||
import { effect } from '@preact/signals-core';
|
||||
|
||||
import { getSurfaceBlock } from '../../surface-ref-block/utils.js';
|
||||
import { RootService } from '../root-service.js';
|
||||
import { GfxBlockModel } from './block-model.js';
|
||||
import type { EdgelessFrameManager } from './frame-manager.js';
|
||||
|
||||
@@ -2,9 +2,10 @@ import type {
|
||||
SurfaceBlockComponent,
|
||||
SurfaceBlockModel,
|
||||
} from '@blocksuite/affine-block-surface';
|
||||
import { Overlay } from '@blocksuite/affine-block-surface';
|
||||
import { getSurfaceBlock, Overlay } from '@blocksuite/affine-block-surface';
|
||||
import type { ConnectorElementModel } from '@blocksuite/affine-model';
|
||||
import type { GfxController } from '@blocksuite/block-std/gfx';
|
||||
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
|
||||
import { Bound, Point } from '@blocksuite/global/utils';
|
||||
|
||||
import { isConnectable } from '../utils/query.js';
|
||||
@@ -52,9 +53,13 @@ export class EdgelessSnapManager extends Overlay {
|
||||
};
|
||||
|
||||
private get _surface() {
|
||||
const surfaceModel = this.gfx.doc.getBlockByFlavour(
|
||||
'affine:surface'
|
||||
)[0] as SurfaceBlockModel;
|
||||
const surfaceModel = getSurfaceBlock(this.gfx.doc);
|
||||
if (!surfaceModel) {
|
||||
throw new BlockSuiteError(
|
||||
ErrorCode.ValueNotExists,
|
||||
'Surface block not found in doc when creating snap manager'
|
||||
);
|
||||
}
|
||||
|
||||
return this.gfx.std.view.getBlock(surfaceModel.id) as SurfaceBlockComponent;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { addSiblingAttachmentBlocks } from '@blocksuite/affine-block-attachment';
|
||||
import { getSurfaceBlock } from '@blocksuite/affine-block-surface';
|
||||
import {
|
||||
getInlineEditorByModel,
|
||||
insertContent,
|
||||
@@ -61,7 +62,6 @@ import { cssVarV2 } from '@toeverything/theme/v2';
|
||||
import type { TemplateResult } from 'lit';
|
||||
|
||||
import { toggleEmbedCardCreateModal } from '../../../_common/components/embed-card/modal/embed-card-create-modal.js';
|
||||
import { getSurfaceBlock } from '../../../surface-ref-block/utils.js';
|
||||
import type { PageRootBlockComponent } from '../../page/page-root-block.js';
|
||||
import { formatDate, formatTime } from '../../utils/misc.js';
|
||||
import type { AffineLinkedDocWidget } from '../linked-doc/index.js';
|
||||
|
||||
@@ -77,8 +77,12 @@ export type LinkedMenuGroup = {
|
||||
styles?: string;
|
||||
// maximum quantity displayed by default
|
||||
maxDisplay?: number;
|
||||
// if the menu is loading
|
||||
loading?: boolean | Signal<boolean>;
|
||||
// copywriting when display quantity exceeds
|
||||
overflowText?: string;
|
||||
overflowText?: string | Signal<string>;
|
||||
// loading text
|
||||
loadingText?: string | Signal<string>;
|
||||
};
|
||||
|
||||
export type LinkedDocContext = {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { LoadingIcon } from '@blocksuite/affine-block-image';
|
||||
import type { IconButton } from '@blocksuite/affine-components/icon-button';
|
||||
import { MoreHorizontalIcon } from '@blocksuite/affine-components/icons';
|
||||
import {
|
||||
@@ -90,15 +91,26 @@ export class LinkedDocPopover extends SignalWatcher(
|
||||
|
||||
private _getActionItems(group: LinkedMenuGroup) {
|
||||
const isExpanded = !!this._expanded.get(group.name);
|
||||
const items = resolveSignal(group.items);
|
||||
if (isExpanded) {
|
||||
return items;
|
||||
}
|
||||
let items = resolveSignal(group.items);
|
||||
|
||||
const isOverflow = !!group.maxDisplay && items.length > group.maxDisplay;
|
||||
if (isOverflow) {
|
||||
return items.slice(0, group.maxDisplay).concat({
|
||||
const isLoading = resolveSignal(group.loading);
|
||||
|
||||
items = isExpanded ? items : items.slice(0, group.maxDisplay);
|
||||
|
||||
if (isLoading) {
|
||||
items = items.concat({
|
||||
key: 'loading',
|
||||
name: resolveSignal(group.loadingText) || 'loading',
|
||||
icon: LoadingIcon,
|
||||
action: () => {},
|
||||
});
|
||||
}
|
||||
|
||||
if (isOverflow && !isExpanded && group.maxDisplay) {
|
||||
items = items.concat({
|
||||
key: `${group.name} More`,
|
||||
name: group.overflowText || 'more',
|
||||
name: resolveSignal(group.overflowText) || 'more',
|
||||
icon: MoreHorizontalIcon,
|
||||
action: () => {
|
||||
this._expanded.set(group.name, true);
|
||||
@@ -106,6 +118,7 @@ export class LinkedDocPopover extends SignalWatcher(
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
LoomIcon,
|
||||
YoutubeIcon,
|
||||
} from '@blocksuite/affine-block-embed';
|
||||
import { getSurfaceBlock } from '@blocksuite/affine-block-surface';
|
||||
import {
|
||||
ArrowDownBigIcon,
|
||||
ArrowUpBigIcon,
|
||||
@@ -51,7 +52,6 @@ import type { TemplateResult } from 'lit';
|
||||
|
||||
import { toggleEmbedCardCreateModal } from '../../../_common/components/embed-card/modal/embed-card-create-modal.js';
|
||||
import type { DataViewBlockComponent } from '../../../data-view-block/index.js';
|
||||
import { getSurfaceBlock } from '../../../surface-ref-block/utils.js';
|
||||
import type { RootBlockComponent } from '../../types.js';
|
||||
import { formatDate, formatTime } from '../../utils/misc.js';
|
||||
import type { AffineLinkedDocWidget } from '../linked-doc/index.js';
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { getSurfaceBlock } from '@blocksuite/affine-block-surface';
|
||||
import type { SurfaceRefProps } from '@blocksuite/affine-model';
|
||||
import { matchFlavours } from '@blocksuite/affine-shared/utils';
|
||||
import type { BlockCommands, Command } from '@blocksuite/block-std';
|
||||
|
||||
import { getSurfaceBlock } from './utils.js';
|
||||
|
||||
export const insertSurfaceRefBlockCommand: Command<
|
||||
'selectedModels',
|
||||
'insertedSurfaceRefBlockId',
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
getSurfaceBlock,
|
||||
type SurfaceBlockModel,
|
||||
SurfaceElementModel,
|
||||
} from '@blocksuite/affine-block-surface';
|
||||
@@ -306,10 +307,7 @@ export class SurfaceRefBlockComponent extends BlockComponent<SurfaceRefBlockMode
|
||||
}
|
||||
|
||||
private _initReferencedModel() {
|
||||
const surfaceModel: SurfaceBlockModel | null =
|
||||
(this.doc.getBlocksByFlavour('affine:surface')[0]?.model as
|
||||
| SurfaceBlockModel
|
||||
| undefined) ?? null;
|
||||
const surfaceModel = getSurfaceBlock(this.doc);
|
||||
this._surfaceModel = surfaceModel;
|
||||
|
||||
const findReferencedModel = (): [
|
||||
@@ -338,15 +336,11 @@ export class SurfaceRefBlockComponent extends BlockComponent<SurfaceRefBlockMode
|
||||
.find(
|
||||
doc =>
|
||||
doc.getBlock(this.model.reference) ||
|
||||
(
|
||||
doc.getBlocksByFlavour('affine:surface')[0]
|
||||
.model as SurfaceBlockModel
|
||||
).getElementById(this.model.reference)
|
||||
getSurfaceBlock(doc)!.getElementById(this.model.reference)
|
||||
);
|
||||
|
||||
if (doc) {
|
||||
this._surfaceModel = doc.getBlocksByFlavour('affine:surface')[0]
|
||||
.model as SurfaceBlockModel;
|
||||
this._surfaceModel = getSurfaceBlock(doc);
|
||||
}
|
||||
|
||||
if (doc && doc.getBlock(this.model.reference)) {
|
||||
@@ -356,12 +350,9 @@ export class SurfaceRefBlockComponent extends BlockComponent<SurfaceRefBlockMode
|
||||
];
|
||||
}
|
||||
|
||||
if (doc && doc.getBlocksByFlavour('affine:surface')[0]) {
|
||||
if (doc && getSurfaceBlock(doc)) {
|
||||
return [
|
||||
(
|
||||
doc.getBlocksByFlavour('affine:surface')[0]
|
||||
.model as SurfaceBlockModel
|
||||
).getElementById(this.model.reference),
|
||||
getSurfaceBlock(doc)!.getElementById(this.model.reference),
|
||||
doc.id,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
import type { SurfaceBlockModel } from '@blocksuite/affine-block-surface';
|
||||
import type { Doc } from '@blocksuite/store';
|
||||
import { html } from 'lit';
|
||||
|
||||
export function getSurfaceBlock(doc: Doc) {
|
||||
const blocks = doc.getBlocksByFlavour('affine:surface');
|
||||
return blocks.length !== 0 ? (blocks[0].model as SurfaceBlockModel) : null;
|
||||
}
|
||||
|
||||
export const noContentPlaceholder = html`
|
||||
<svg
|
||||
width="182"
|
||||
|
||||
@@ -55,6 +55,9 @@
|
||||
{
|
||||
"path": "../affine/block-image"
|
||||
},
|
||||
{
|
||||
"path": "../affine/block-edgeless-text"
|
||||
},
|
||||
{
|
||||
"path": "../affine/data-view"
|
||||
},
|
||||
|
||||
@@ -273,6 +273,8 @@ class DragController extends PointerControllerBase {
|
||||
};
|
||||
|
||||
private readonly _nativeDragOver = (event: DragEvent) => {
|
||||
// prevent default to allow drop in editor
|
||||
event.preventDefault();
|
||||
const dndEventState = new DndEventState({ event });
|
||||
this._dispatcher.run(
|
||||
'nativeDragOver',
|
||||
|
||||
@@ -17,6 +17,7 @@ import '@shoelace-style/shoelace/dist/themes/dark.css';
|
||||
import './left-side-panel.js';
|
||||
import './side-panel.js';
|
||||
|
||||
import { NotionHtmlAdapter } from '@blocksuite/affine-shared/adapters';
|
||||
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
|
||||
import { ShadowlessElement } from '@blocksuite/block-std';
|
||||
import {
|
||||
@@ -35,7 +36,6 @@ import {
|
||||
HtmlTransformer,
|
||||
MarkdownAdapterFactoryIdentifier,
|
||||
MarkdownTransformer,
|
||||
NotionHtmlAdapter,
|
||||
NotionHtmlTransformer,
|
||||
openFileOrFiles,
|
||||
PlainTextAdapterFactoryIdentifier,
|
||||
@@ -435,7 +435,7 @@ export class StarterDebugMenu extends ShadowlessElement {
|
||||
collection: this.collection,
|
||||
middlewares: [defaultImageProxyMiddleware],
|
||||
});
|
||||
const htmlAdapter = new NotionHtmlAdapter(job);
|
||||
const htmlAdapter = new NotionHtmlAdapter(job, this.editor.std.provider);
|
||||
await htmlAdapter.toDoc({
|
||||
file: await file.text(),
|
||||
pageId: this.collection.idGenerator(),
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
".vscode",
|
||||
".yarnrc.yml",
|
||||
".docker",
|
||||
"**/.storybook",
|
||||
".coverage",
|
||||
".nx/**",
|
||||
"target",
|
||||
@@ -33,8 +34,7 @@
|
||||
"packages/frontend/graphql/src/graphql/index.ts",
|
||||
"packages/frontend/graphql/src/schema.ts",
|
||||
"packages/frontend/apps/android/App/app/build/**",
|
||||
"blocksuite/tests-legacy/snapshots",
|
||||
"**/.storybook"
|
||||
"blocksuite/tests-legacy/snapshots"
|
||||
],
|
||||
"rules": {
|
||||
"import/named": "allow",
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
"node": "<21.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"affine": "yarn workspace @affine-tools/cli affine",
|
||||
"af": "yarn workspace @affine-tools/cli affine",
|
||||
"affine": "r affine.ts",
|
||||
"af": "r affine.ts",
|
||||
"dev": "yarn affine dev",
|
||||
"build": "yarn affine build",
|
||||
"lint:eslint": "cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" eslint --report-unused-disable-directives-severity=off . --cache",
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Please do not edit this file manually
|
||||
# It should be added in your version-control system (i.e. Git)
|
||||
provider = "postgresql"
|
||||
provider = "postgresql"
|
||||
|
||||
@@ -34,7 +34,6 @@ const OIDCConfigurationSchema = z.object({
|
||||
authorization_endpoint: z.string().url(),
|
||||
token_endpoint: z.string().url(),
|
||||
userinfo_endpoint: z.string().url(),
|
||||
end_session_endpoint: z.string().url(),
|
||||
});
|
||||
|
||||
type OIDCConfiguration = z.infer<typeof OIDCConfigurationSchema>;
|
||||
|
||||
@@ -45,6 +45,7 @@ function loadPrivateKey() {
|
||||
}
|
||||
|
||||
async function load() {
|
||||
let isPrivateKeyFromEnv = !!process.env.AFFINE_PRIVATE_KEY;
|
||||
// Initializing AFFiNE config
|
||||
//
|
||||
// 1. load dotenv file to `process.env`
|
||||
@@ -56,6 +57,12 @@ async function load() {
|
||||
path: join(CUSTOM_CONFIG_PATH, '.env'),
|
||||
});
|
||||
|
||||
// @deprecated
|
||||
// The old AFFINE_PRIVATE_KEY in old .env is somehow not working, we should ignore it
|
||||
if (!isPrivateKeyFromEnv) {
|
||||
delete process.env.AFFINE_PRIVATE_KEY;
|
||||
}
|
||||
|
||||
// 2. generate AFFiNE default config and assign to `globalThis.AFFiNE`
|
||||
globalThis.AFFiNE = getAFFiNEConfigModifier();
|
||||
const { enablePlugin } = await import('./plugins/registry');
|
||||
|
||||
@@ -9,9 +9,9 @@ rand = { workspace = true }
|
||||
sha3 = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
rayon = { workspace = true }
|
||||
criterion2 = { workspace = true }
|
||||
criterion2 = { workspace = true }
|
||||
rayon = { workspace = true }
|
||||
|
||||
[[bench]]
|
||||
name = "hashcash"
|
||||
harness = false
|
||||
name = "hashcash"
|
||||
|
||||
@@ -13,6 +13,10 @@ export function universalId({ peer, type, id }: StorageOptions) {
|
||||
return `@peer(${peer});@type(${type});@id(${id});`;
|
||||
}
|
||||
|
||||
export function isValidSpaceType(type: string): type is SpaceType {
|
||||
return type === 'workspace' || type === 'userspace';
|
||||
}
|
||||
|
||||
export function isValidUniversalId(opts: Record<string, string>): boolean {
|
||||
const requiredKeys: Array<keyof StorageOptions> = [
|
||||
'peer',
|
||||
@@ -26,11 +30,11 @@ export function isValidUniversalId(opts: Record<string, string>): boolean {
|
||||
}
|
||||
}
|
||||
|
||||
return opts.type === 'userspace' || opts.type === 'workspace';
|
||||
return isValidSpaceType(opts.type);
|
||||
}
|
||||
|
||||
export function parseUniversalId(id: string) {
|
||||
const result: Record<string, string> = {};
|
||||
const result: Partial<StorageOptions> = {};
|
||||
let key = '';
|
||||
let value = '';
|
||||
let isInValue = false;
|
||||
@@ -44,6 +48,7 @@ export function parseUniversalId(id: string) {
|
||||
// when we are in value string, we only care about ch and next char to be [')', ';'] to end the id part
|
||||
if (isInValue) {
|
||||
if (ch === ')' && nextCh === ';') {
|
||||
// @ts-expect-error we know the key is valid
|
||||
result[key] = value;
|
||||
key = '';
|
||||
value = '';
|
||||
@@ -77,7 +82,7 @@ export function parseUniversalId(id: string) {
|
||||
);
|
||||
}
|
||||
|
||||
return result as any;
|
||||
return result as StorageOptions;
|
||||
}
|
||||
|
||||
export interface Storage {
|
||||
|
||||
@@ -60,6 +60,10 @@
|
||||
FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.debug.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||
C45499AB2D140B5000E21978 /* NBStore */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = NBStore; sourceTree = "<group>"; };
|
||||
/* End PBXFileSystemSynchronizedRootGroup section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
504EC3011FED79650016851F /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
@@ -139,6 +143,7 @@
|
||||
9D90BE1A2CCB9876006677DB /* Plugins */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C45499AB2D140B5000E21978 /* NBStore */,
|
||||
E93B276A2CED9298001409B8 /* NavigationGesture */,
|
||||
9D90BE192CCB9876006677DB /* Cookie */,
|
||||
);
|
||||
@@ -201,6 +206,9 @@
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
fileSystemSynchronizedGroups = (
|
||||
C45499AB2D140B5000E21978 /* NBStore */,
|
||||
);
|
||||
name = App;
|
||||
productName = App;
|
||||
productReference = 504EC3041FED79650016851F /* App.app */;
|
||||
|
||||
@@ -20,6 +20,7 @@ class AFFiNEViewController: CAPBridgeViewController {
|
||||
HashcashPlugin(),
|
||||
NavigationGesturePlugin(),
|
||||
IntelligentsPlugin(representController: self),
|
||||
NbStorePlugin(),
|
||||
]
|
||||
plugins.forEach { bridge?.registerPluginInstance($0) }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,402 @@
|
||||
import Capacitor
|
||||
import Foundation
|
||||
|
||||
@objc(NbStorePlugin)
|
||||
public class NbStorePlugin: CAPPlugin, CAPBridgedPlugin {
|
||||
private let docStoragePool: DocStoragePool = .init(noPointer: DocStoragePool.NoPointer())
|
||||
|
||||
public let identifier = "NbStorePlugin"
|
||||
public let jsName = "NbStoreDocStorage"
|
||||
public let pluginMethods: [CAPPluginMethod] = [
|
||||
CAPPluginMethod(name: "getSpaceDBPath", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "connect", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "close", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "isClosed", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "checkpoint", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "validate", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "setSpaceId", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "pushUpdate", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "getDocSnapshot", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "setDocSnapshot", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "getDocUpdates", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "markUpdatesMerged", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "deleteDoc", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "getDocClocks", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "getDocClock", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "getBlob", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "setBlob", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "deleteBlob", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "releaseBlobs", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "listBlobs", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "getPeerRemoteClocks", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "getPeerRemoteClock", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "setPeerRemoteClock", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "getPeerPulledRemoteClocks", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "getPeerPulledRemoteClock", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "setPeerPulledRemoteClock", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "getPeerPushedClocks", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "setPeerPushedClock", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "clearClocks", returnType: CAPPluginReturnPromise),
|
||||
]
|
||||
|
||||
@objc func getSpaceDBPath(_ call: CAPPluginCall) {
|
||||
let peer = call.getString("peer") ?? ""
|
||||
let spaceType = call.getString("spaceType") ?? ""
|
||||
let id = call.getString("id") ?? ""
|
||||
|
||||
do {
|
||||
let path = try getDbPath(peer: peer, spaceType: spaceType, id: id)
|
||||
call.resolve(["path": path])
|
||||
} catch {
|
||||
call.reject("Failed to get space DB path", nil, error)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func connect(_ call: CAPPluginCall) async {
|
||||
let id = call.getString("id") ?? ""
|
||||
try? await docStoragePool.connect(universalId: id)
|
||||
}
|
||||
|
||||
@objc func close(_ call: CAPPluginCall) async {
|
||||
let id = call.getString("id") ?? ""
|
||||
try? await docStoragePool.close(universalId: id)
|
||||
}
|
||||
|
||||
@objc func isClosed(_ call: CAPPluginCall) {
|
||||
let id = call.getString("id") ?? ""
|
||||
call.resolve(["isClosed": docStoragePool.isClosed(universalId: id)])
|
||||
}
|
||||
|
||||
@objc func checkpoint(_ call: CAPPluginCall) async {
|
||||
let id = call.getString("id") ?? ""
|
||||
try? await docStoragePool.checkpoint(universalId: id)
|
||||
}
|
||||
|
||||
@objc func validate(_ call: CAPPluginCall) async {
|
||||
let id = call.getString("id") ?? ""
|
||||
let validate = (try? await docStoragePool.validate(universalId: id)) ?? false
|
||||
call.resolve(["isValidate": validate])
|
||||
}
|
||||
|
||||
@objc func setSpaceId(_ call: CAPPluginCall) async {
|
||||
let id = call.getString("id") ?? ""
|
||||
let spaceId = call.getString("spaceId") ?? ""
|
||||
do {
|
||||
try await docStoragePool.setSpaceId(universalId: id, spaceId: spaceId)
|
||||
call.resolve()
|
||||
} catch {
|
||||
call.reject("Failed to set space id", nil, error)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func pushUpdate(_ call: CAPPluginCall) async {
|
||||
let id = call.getString("id") ?? ""
|
||||
let docId = call.getString("docId") ?? ""
|
||||
let data = call.getString("data") ?? ""
|
||||
do {
|
||||
let timestamp = try await docStoragePool.pushUpdate(universalId: id, docId: docId, update: data)
|
||||
call.resolve(["timestamp": timestamp.timeIntervalSince1970])
|
||||
|
||||
} catch {
|
||||
call.reject("Failed to push update", nil, error)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func getDocSnapshot(_ call: CAPPluginCall) async {
|
||||
let id = call.getString("id") ?? ""
|
||||
let docId = call.getString("docId") ?? ""
|
||||
do {
|
||||
if let record = try await docStoragePool.getDocSnapshot(universalId: id, docId: docId) {
|
||||
call.resolve([
|
||||
"docId": record.docId,
|
||||
"data": record.data,
|
||||
"timestamp": record.timestamp.timeIntervalSince1970,
|
||||
])
|
||||
} else {
|
||||
call.resolve()
|
||||
}
|
||||
} catch {
|
||||
call.reject("Failed to get doc snapshot", nil, error)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func setDocSnapshot(_ call: CAPPluginCall) async {
|
||||
let id = call.getString("id") ?? ""
|
||||
let docId = call.getString("docId") ?? ""
|
||||
let data = call.getString("data") ?? ""
|
||||
let timestamp = Date()
|
||||
do {
|
||||
let success = try await docStoragePool.setDocSnapshot(
|
||||
universalId: id,
|
||||
snapshot: DocRecord(docId: docId, data: data, timestamp: timestamp)
|
||||
)
|
||||
call.resolve(["success": success])
|
||||
} catch {
|
||||
call.reject("Failed to set doc snapshot", nil, error)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func getDocUpdates(_ call: CAPPluginCall) async {
|
||||
let id = call.getString("id") ?? ""
|
||||
let docId = call.getString("docId") ?? ""
|
||||
do {
|
||||
let updates = try await docStoragePool.getDocUpdates(universalId: id, docId: docId)
|
||||
let mapped = updates.map { [
|
||||
"docId": $0.docId,
|
||||
"createdAt": $0.createdAt.timeIntervalSince1970,
|
||||
"data": $0.data,
|
||||
] }
|
||||
call.resolve(["updates": mapped])
|
||||
} catch {
|
||||
call.reject("Failed to get doc updates", nil, error)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func markUpdatesMerged(_ call: CAPPluginCall) async {
|
||||
let id = call.getString("id") ?? ""
|
||||
let docId = call.getString("docId") ?? ""
|
||||
let times = call.getArray("timestamps", Double.self) ?? []
|
||||
let dateArray = times.map { Date(timeIntervalSince1970: $0) }
|
||||
do {
|
||||
let count = try await docStoragePool.markUpdatesMerged(universalId: id, docId: docId, updates: dateArray)
|
||||
call.resolve(["count": count])
|
||||
} catch {
|
||||
call.reject("Failed to mark updates merged", nil, error)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func deleteDoc(_ call: CAPPluginCall) async {
|
||||
let id = call.getString("id") ?? ""
|
||||
let docId = call.getString("docId") ?? ""
|
||||
do {
|
||||
try await docStoragePool.deleteDoc(universalId: id, docId: docId)
|
||||
call.resolve()
|
||||
} catch {
|
||||
call.reject("Failed to delete doc", nil, error)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func getDocClocks(_ call: CAPPluginCall) async {
|
||||
let id = call.getString("id") ?? ""
|
||||
let after = call.getInt("after")
|
||||
do {
|
||||
let docClocks = try await docStoragePool.getDocClocks(
|
||||
universalId: id,
|
||||
after: after != nil ? Date(timeIntervalSince1970: TimeInterval(after!)) : nil
|
||||
)
|
||||
let mapped = docClocks.map { [
|
||||
"docId": $0.docId,
|
||||
"timestamp": $0.timestamp.timeIntervalSince1970,
|
||||
] }
|
||||
call.resolve(["clocks": mapped])
|
||||
} catch {
|
||||
call.reject("Failed to get doc clocks", nil, error)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func getDocClock(_ call: CAPPluginCall) async {
|
||||
let id = call.getString("id") ?? ""
|
||||
let docId = call.getString("docId") ?? ""
|
||||
do {
|
||||
if let docClock = try await docStoragePool.getDocClock(universalId: id, docId: docId) {
|
||||
call.resolve([
|
||||
"docId": docClock.docId,
|
||||
"timestamp": docClock.timestamp.timeIntervalSince1970,
|
||||
])
|
||||
} else {
|
||||
call.resolve()
|
||||
}
|
||||
} catch {
|
||||
call.reject("Failed to get doc clock for docId: \(docId)", nil, error)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func getBlob(_ call: CAPPluginCall) async {
|
||||
let id = call.getString("id") ?? ""
|
||||
let key = call.getString("key") ?? ""
|
||||
if let blob = try? await docStoragePool.getBlob(universalId: id, key: key) {
|
||||
call.resolve(["blob": blob])
|
||||
} else {
|
||||
call.resolve()
|
||||
}
|
||||
}
|
||||
|
||||
@objc func setBlob(_ call: CAPPluginCall) async {
|
||||
let id = call.getString("id") ?? ""
|
||||
let key = call.getString("key") ?? ""
|
||||
let data = call.getString("data") ?? ""
|
||||
let mime = call.getString("mime") ?? ""
|
||||
try? await docStoragePool.setBlob(universalId: id, blob: SetBlob(key: key, data: data, mime: mime))
|
||||
}
|
||||
|
||||
@objc func deleteBlob(_ call: CAPPluginCall) async {
|
||||
let id = call.getString("id") ?? ""
|
||||
let key = call.getString("key") ?? ""
|
||||
let permanently = call.getBool("permanently") ?? false
|
||||
try? await docStoragePool.deleteBlob(universalId: id, key: key, permanently: permanently)
|
||||
}
|
||||
|
||||
@objc func releaseBlobs(_ call: CAPPluginCall) async {
|
||||
let id = call.getString("id") ?? ""
|
||||
try? await docStoragePool.releaseBlobs(universalId: id)
|
||||
}
|
||||
|
||||
@objc func listBlobs(_ call: CAPPluginCall) async {
|
||||
let id = call.getString("id") ?? ""
|
||||
if let blobs = try? await docStoragePool.listBlobs(universalId: id) {
|
||||
let mapped = blobs.map { [
|
||||
"key": $0.key,
|
||||
"size": $0.size,
|
||||
"mime": $0.mime,
|
||||
"createdAt": $0.createdAt.timeIntervalSince1970,
|
||||
] }
|
||||
call.resolve(["blobs": mapped])
|
||||
} else {
|
||||
call.resolve()
|
||||
}
|
||||
}
|
||||
|
||||
@objc func getPeerRemoteClocks(_ call: CAPPluginCall) async {
|
||||
let id = call.getString("id") ?? ""
|
||||
let peer = call.getString("peer") ?? ""
|
||||
do {
|
||||
let clocks = try await docStoragePool.getPeerRemoteClocks(universalId: id, peer: peer)
|
||||
let mapped = clocks.map { [
|
||||
"docId": $0.docId,
|
||||
"timestamp": $0.timestamp.timeIntervalSince1970,
|
||||
] }
|
||||
call.resolve(["clocks": mapped])
|
||||
|
||||
} catch {
|
||||
call.reject("Failed to get peer remote clocks", nil, error)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func getPeerRemoteClock(_ call: CAPPluginCall) async {
|
||||
let id = call.getString("id") ?? ""
|
||||
let peer = call.getString("peer") ?? ""
|
||||
let docId = call.getString("docId") ?? ""
|
||||
do {
|
||||
let clock = try await docStoragePool.getPeerRemoteClock(universalId: id, peer: peer, docId: docId)
|
||||
call.resolve([
|
||||
"docId": clock.docId,
|
||||
"timestamp": clock.timestamp.timeIntervalSince1970,
|
||||
])
|
||||
|
||||
} catch {
|
||||
call.reject("Failed to get peer remote clock", nil, error)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func setPeerRemoteClock(_ call: CAPPluginCall) async {
|
||||
let id = call.getString("id") ?? ""
|
||||
let peer = call.getString("peer") ?? ""
|
||||
let docId = call.getString("docId") ?? ""
|
||||
let timestamp = call.getDouble("timestamp") ?? 0
|
||||
do {
|
||||
try await docStoragePool.setPeerRemoteClock(
|
||||
universalId: id,
|
||||
peer: peer,
|
||||
docId: docId,
|
||||
clock: Date(timeIntervalSince1970: timestamp)
|
||||
)
|
||||
call.resolve()
|
||||
} catch {
|
||||
call.reject("Failed to set peer remote clock", nil, error)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func getPeerPulledRemoteClocks(_ call: CAPPluginCall) async {
|
||||
let id = call.getString("id") ?? ""
|
||||
let peer = call.getString("peer") ?? ""
|
||||
do {
|
||||
let clocks = try await docStoragePool.getPeerPulledRemoteClocks(universalId: id, peer: peer)
|
||||
let mapped = clocks.map { [
|
||||
"docId": $0.docId,
|
||||
"timestamp": $0.timestamp.timeIntervalSince1970,
|
||||
] }
|
||||
call.resolve(["clocks": mapped])
|
||||
|
||||
} catch {
|
||||
call.reject("Failed to get peer pulled remote clocks", nil, error)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func getPeerPulledRemoteClock(_ call: CAPPluginCall) async {
|
||||
let id = call.getString("id") ?? ""
|
||||
let peer = call.getString("peer") ?? ""
|
||||
let docId = call.getString("docId") ?? ""
|
||||
do {
|
||||
let clock = try await docStoragePool.getPeerPulledRemoteClock(universalId: id, peer: peer, docId: docId)
|
||||
call.resolve([
|
||||
"docId": clock.docId,
|
||||
"timestamp": clock.timestamp.timeIntervalSince1970,
|
||||
])
|
||||
|
||||
} catch {
|
||||
call.reject("Failed to get peer pulled remote clock", nil, error)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func setPeerPulledRemoteClock(_ call: CAPPluginCall) async {
|
||||
let id = call.getString("id") ?? ""
|
||||
let peer = call.getString("peer") ?? ""
|
||||
let docId = call.getString("docId") ?? ""
|
||||
let timestamp = call.getDouble("timestamp") ?? 0
|
||||
do {
|
||||
try await docStoragePool.setPeerPulledRemoteClock(
|
||||
universalId: id,
|
||||
peer: peer,
|
||||
docId: docId,
|
||||
clock: Date(timeIntervalSince1970: timestamp)
|
||||
)
|
||||
call.resolve()
|
||||
} catch {
|
||||
call.reject("Failed to set peer pulled remote clock", nil, error)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func getPeerPushedClocks(_ call: CAPPluginCall) async {
|
||||
let id = call.getString("id") ?? ""
|
||||
let peer = call.getString("peer") ?? ""
|
||||
do {
|
||||
let clocks = try await docStoragePool.getPeerPushedClocks(universalId: id, peer: peer)
|
||||
let mapped = clocks.map { [
|
||||
"docId": $0.docId,
|
||||
"timestamp": $0.timestamp.timeIntervalSince1970,
|
||||
] }
|
||||
call.resolve(["clocks": mapped])
|
||||
|
||||
} catch {
|
||||
call.reject("Failed to get peer pushed clocks", nil, error)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func setPeerPushedClock(_ call: CAPPluginCall) async {
|
||||
let id = call.getString("id") ?? ""
|
||||
let peer = call.getString("peer") ?? ""
|
||||
let docId = call.getString("docId") ?? ""
|
||||
let timestamp = call.getDouble("timestamp") ?? 0
|
||||
do {
|
||||
try await docStoragePool.setPeerPushedClock(
|
||||
universalId: id,
|
||||
peer: peer,
|
||||
docId: docId,
|
||||
clock: Date(timeIntervalSince1970: timestamp)
|
||||
)
|
||||
call.resolve()
|
||||
} catch {
|
||||
call.reject("Failed to set peer pushed clock", nil, error)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func clearClocks(_ call: CAPPluginCall) async {
|
||||
let id = call.getString("id") ?? ""
|
||||
do {
|
||||
try await docStoragePool.clearClocks(universalId: id)
|
||||
call.resolve()
|
||||
} catch {
|
||||
call.reject("Failed to clear clocks", nil, error)
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -250,6 +250,161 @@ typedef struct UniffiForeignFutureStructVoid {
|
||||
typedef void (*UniffiForeignFutureCompleteVoid)(uint64_t, UniffiForeignFutureStructVoid
|
||||
);
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_CLONE_DOCSTORAGEPOOL
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_CLONE_DOCSTORAGEPOOL
|
||||
void*_Nonnull uniffi_affine_mobile_native_fn_clone_docstoragepool(void*_Nonnull ptr, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_FREE_DOCSTORAGEPOOL
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_FREE_DOCSTORAGEPOOL
|
||||
void uniffi_affine_mobile_native_fn_free_docstoragepool(void*_Nonnull ptr, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_CHECKPOINT
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_CHECKPOINT
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_checkpoint(void*_Nonnull ptr, RustBuffer universal_id
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_CLEAR_CLOCKS
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_CLEAR_CLOCKS
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_clear_clocks(void*_Nonnull ptr, RustBuffer universal_id
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_CLOSE
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_CLOSE
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_close(void*_Nonnull ptr, RustBuffer universal_id
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_CONNECT
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_CONNECT
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_connect(void*_Nonnull ptr, RustBuffer universal_id
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_DELETE_BLOB
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_DELETE_BLOB
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_delete_blob(void*_Nonnull ptr, RustBuffer universal_id, RustBuffer key, int8_t permanently
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_DELETE_DOC
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_DELETE_DOC
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_delete_doc(void*_Nonnull ptr, RustBuffer universal_id, RustBuffer doc_id
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_GET_BLOB
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_GET_BLOB
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_get_blob(void*_Nonnull ptr, RustBuffer universal_id, RustBuffer key
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_GET_DOC_CLOCK
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_GET_DOC_CLOCK
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_get_doc_clock(void*_Nonnull ptr, RustBuffer universal_id, RustBuffer doc_id
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_GET_DOC_CLOCKS
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_GET_DOC_CLOCKS
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_get_doc_clocks(void*_Nonnull ptr, RustBuffer universal_id, RustBuffer after
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_GET_DOC_SNAPSHOT
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_GET_DOC_SNAPSHOT
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_get_doc_snapshot(void*_Nonnull ptr, RustBuffer universal_id, RustBuffer doc_id
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_GET_DOC_UPDATES
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_GET_DOC_UPDATES
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_get_doc_updates(void*_Nonnull ptr, RustBuffer universal_id, RustBuffer doc_id
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_GET_PEER_PULLED_REMOTE_CLOCK
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_GET_PEER_PULLED_REMOTE_CLOCK
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_get_peer_pulled_remote_clock(void*_Nonnull ptr, RustBuffer universal_id, RustBuffer peer, RustBuffer doc_id
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_GET_PEER_PULLED_REMOTE_CLOCKS
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_GET_PEER_PULLED_REMOTE_CLOCKS
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_get_peer_pulled_remote_clocks(void*_Nonnull ptr, RustBuffer universal_id, RustBuffer peer
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_GET_PEER_PUSHED_CLOCKS
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_GET_PEER_PUSHED_CLOCKS
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_get_peer_pushed_clocks(void*_Nonnull ptr, RustBuffer universal_id, RustBuffer peer
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_GET_PEER_REMOTE_CLOCK
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_GET_PEER_REMOTE_CLOCK
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_get_peer_remote_clock(void*_Nonnull ptr, RustBuffer universal_id, RustBuffer peer, RustBuffer doc_id
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_GET_PEER_REMOTE_CLOCKS
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_GET_PEER_REMOTE_CLOCKS
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_get_peer_remote_clocks(void*_Nonnull ptr, RustBuffer universal_id, RustBuffer peer
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_IS_CLOSED
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_IS_CLOSED
|
||||
int8_t uniffi_affine_mobile_native_fn_method_docstoragepool_is_closed(void*_Nonnull ptr, RustBuffer universal_id, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_LIST_BLOBS
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_LIST_BLOBS
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_list_blobs(void*_Nonnull ptr, RustBuffer universal_id
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_MARK_UPDATES_MERGED
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_MARK_UPDATES_MERGED
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_mark_updates_merged(void*_Nonnull ptr, RustBuffer universal_id, RustBuffer doc_id, RustBuffer updates
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_PUSH_UPDATE
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_PUSH_UPDATE
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_push_update(void*_Nonnull ptr, RustBuffer universal_id, RustBuffer doc_id, RustBuffer update
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_RELEASE_BLOBS
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_RELEASE_BLOBS
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_release_blobs(void*_Nonnull ptr, RustBuffer universal_id
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_SET_BLOB
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_SET_BLOB
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_set_blob(void*_Nonnull ptr, RustBuffer universal_id, RustBuffer blob
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_SET_DOC_SNAPSHOT
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_SET_DOC_SNAPSHOT
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_set_doc_snapshot(void*_Nonnull ptr, RustBuffer universal_id, RustBuffer snapshot
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_SET_PEER_PULLED_REMOTE_CLOCK
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_SET_PEER_PULLED_REMOTE_CLOCK
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_set_peer_pulled_remote_clock(void*_Nonnull ptr, RustBuffer universal_id, RustBuffer peer, RustBuffer doc_id, RustBuffer clock
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_SET_PEER_PUSHED_CLOCK
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_SET_PEER_PUSHED_CLOCK
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_set_peer_pushed_clock(void*_Nonnull ptr, RustBuffer universal_id, RustBuffer peer, RustBuffer doc_id, RustBuffer clock
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_SET_PEER_REMOTE_CLOCK
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_SET_PEER_REMOTE_CLOCK
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_set_peer_remote_clock(void*_Nonnull ptr, RustBuffer universal_id, RustBuffer peer, RustBuffer doc_id, RustBuffer clock
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_SET_SPACE_ID
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_SET_SPACE_ID
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_set_space_id(void*_Nonnull ptr, RustBuffer universal_id, RustBuffer space_id
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_VALIDATE
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_VALIDATE
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_validate(void*_Nonnull ptr, RustBuffer universal_id
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_FUNC_GET_DB_PATH
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_FUNC_GET_DB_PATH
|
||||
RustBuffer uniffi_affine_mobile_native_fn_func_get_db_path(RustBuffer peer, RustBuffer space_type, RustBuffer id, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_FUNC_HASHCASH_MINT
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_FUNC_HASHCASH_MINT
|
||||
@@ -534,12 +689,186 @@ void ffi_affine_mobile_native_rust_future_free_void(uint64_t handle
|
||||
#ifndef UNIFFI_FFIDEF_FFI_AFFINE_MOBILE_NATIVE_RUST_FUTURE_COMPLETE_VOID
|
||||
#define UNIFFI_FFIDEF_FFI_AFFINE_MOBILE_NATIVE_RUST_FUTURE_COMPLETE_VOID
|
||||
void ffi_affine_mobile_native_rust_future_complete_void(uint64_t handle, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_FUNC_GET_DB_PATH
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_FUNC_GET_DB_PATH
|
||||
uint16_t uniffi_affine_mobile_native_checksum_func_get_db_path(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_FUNC_HASHCASH_MINT
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_FUNC_HASHCASH_MINT
|
||||
uint16_t uniffi_affine_mobile_native_checksum_func_hashcash_mint(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_CHECKPOINT
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_CHECKPOINT
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_checkpoint(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_CLEAR_CLOCKS
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_CLEAR_CLOCKS
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_clear_clocks(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_CLOSE
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_CLOSE
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_close(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_CONNECT
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_CONNECT
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_connect(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_DELETE_BLOB
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_DELETE_BLOB
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_delete_blob(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_DELETE_DOC
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_DELETE_DOC
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_delete_doc(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_GET_BLOB
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_GET_BLOB
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_get_blob(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_GET_DOC_CLOCK
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_GET_DOC_CLOCK
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_get_doc_clock(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_GET_DOC_CLOCKS
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_GET_DOC_CLOCKS
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_get_doc_clocks(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_GET_DOC_SNAPSHOT
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_GET_DOC_SNAPSHOT
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_get_doc_snapshot(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_GET_DOC_UPDATES
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_GET_DOC_UPDATES
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_get_doc_updates(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_GET_PEER_PULLED_REMOTE_CLOCK
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_GET_PEER_PULLED_REMOTE_CLOCK
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_get_peer_pulled_remote_clock(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_GET_PEER_PULLED_REMOTE_CLOCKS
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_GET_PEER_PULLED_REMOTE_CLOCKS
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_get_peer_pulled_remote_clocks(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_GET_PEER_PUSHED_CLOCKS
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_GET_PEER_PUSHED_CLOCKS
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_get_peer_pushed_clocks(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_GET_PEER_REMOTE_CLOCK
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_GET_PEER_REMOTE_CLOCK
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_get_peer_remote_clock(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_GET_PEER_REMOTE_CLOCKS
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_GET_PEER_REMOTE_CLOCKS
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_get_peer_remote_clocks(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_IS_CLOSED
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_IS_CLOSED
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_is_closed(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_LIST_BLOBS
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_LIST_BLOBS
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_list_blobs(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_MARK_UPDATES_MERGED
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_MARK_UPDATES_MERGED
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_mark_updates_merged(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_PUSH_UPDATE
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_PUSH_UPDATE
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_push_update(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_RELEASE_BLOBS
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_RELEASE_BLOBS
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_release_blobs(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_SET_BLOB
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_SET_BLOB
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_set_blob(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_SET_DOC_SNAPSHOT
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_SET_DOC_SNAPSHOT
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_set_doc_snapshot(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_SET_PEER_PULLED_REMOTE_CLOCK
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_SET_PEER_PULLED_REMOTE_CLOCK
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_set_peer_pulled_remote_clock(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_SET_PEER_PUSHED_CLOCK
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_SET_PEER_PUSHED_CLOCK
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_set_peer_pushed_clock(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_SET_PEER_REMOTE_CLOCK
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_SET_PEER_REMOTE_CLOCK
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_set_peer_remote_clock(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_SET_SPACE_ID
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_SET_SPACE_ID
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_set_space_id(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_VALIDATE
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_VALIDATE
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_validate(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_AFFINE_MOBILE_NATIVE_UNIFFI_CONTRACT_VERSION
|
||||
|
||||
@@ -71,4 +71,4 @@ for arch in $ARCHS; do
|
||||
esac
|
||||
done
|
||||
|
||||
$HOME/.cargo/bin/cargo run --bin uniffi-bindgen generate --library $SRCROOT/lib${FFI_TARGET}.a --language swift --out-dir $SRCROOT/../../ios/App/App/uniffi
|
||||
$HOME/.cargo/bin/cargo run -p affine_mobile_native --bin uniffi-bindgen generate --library $SRCROOT/lib${FFI_TARGET}.a --language swift --out-dir $SRCROOT/../../ios/App/App/uniffi
|
||||
|
||||
@@ -27,9 +27,11 @@
|
||||
"next-themes": "^0.4.4",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-router-dom": "^6.28.0"
|
||||
"react-router-dom": "^6.28.0",
|
||||
"yjs": "13.6.18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@affine/native": "workspace:*",
|
||||
"@capacitor/cli": "^6.2.0",
|
||||
"@types/react": "^19.0.1",
|
||||
"@types/react-dom": "^19.0.2",
|
||||
|
||||
33
packages/frontend/apps/ios/src/plugins/nbstore/blob.ts
Normal file
33
packages/frontend/apps/ios/src/plugins/nbstore/blob.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { type BlobRecord, BlobStorageBase, share } from '@affine/nbstore';
|
||||
|
||||
import { NativeDBConnection } from './db';
|
||||
|
||||
export class SqliteBlobStorage extends BlobStorageBase {
|
||||
override connection = share(
|
||||
new NativeDBConnection(this.peer, this.spaceType, this.spaceId)
|
||||
);
|
||||
|
||||
get db() {
|
||||
return this.connection.inner;
|
||||
}
|
||||
|
||||
override async get(key: string) {
|
||||
return this.db.getBlob(key);
|
||||
}
|
||||
|
||||
override async set(blob: BlobRecord) {
|
||||
await this.db.setBlob(blob);
|
||||
}
|
||||
|
||||
override async delete(key: string, permanently: boolean) {
|
||||
await this.db.deleteBlob(key, permanently);
|
||||
}
|
||||
|
||||
override async release() {
|
||||
await this.db.releaseBlobs();
|
||||
}
|
||||
|
||||
override async list() {
|
||||
return this.db.listBlobs();
|
||||
}
|
||||
}
|
||||
60
packages/frontend/apps/ios/src/plugins/nbstore/db.ts
Normal file
60
packages/frontend/apps/ios/src/plugins/nbstore/db.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import type { DocStorage } from '@affine/native';
|
||||
import {
|
||||
AutoReconnectConnection,
|
||||
isValidSpaceType,
|
||||
type SpaceType,
|
||||
universalId,
|
||||
} from '@affine/nbstore';
|
||||
|
||||
import { NativeDocStorage, NbStoreDocStorage } from './plugin';
|
||||
|
||||
export class NativeDBConnection extends AutoReconnectConnection<DocStorage> {
|
||||
private readonly universalId: string;
|
||||
|
||||
constructor(
|
||||
private readonly peer: string,
|
||||
private readonly type: SpaceType,
|
||||
private readonly id: string
|
||||
) {
|
||||
super();
|
||||
if (!isValidSpaceType(type)) {
|
||||
throw new TypeError(`Invalid space type: ${type}`);
|
||||
}
|
||||
this.universalId = universalId({
|
||||
peer: peer,
|
||||
type: type,
|
||||
id: id,
|
||||
});
|
||||
}
|
||||
|
||||
async getDBPath() {
|
||||
const { path } = await NbStoreDocStorage.getSpaceDBPath({
|
||||
peer: this.peer,
|
||||
spaceType: this.type,
|
||||
id: this.id,
|
||||
});
|
||||
return path;
|
||||
}
|
||||
|
||||
override get shareId(): string {
|
||||
return `sqlite:${this.peer}:${this.type}:${this.id}`;
|
||||
}
|
||||
|
||||
override async doConnect() {
|
||||
const conn = new NativeDocStorage(this.universalId);
|
||||
await conn.connect();
|
||||
console.info('[nbstore] connection established', this.shareId);
|
||||
return conn;
|
||||
}
|
||||
|
||||
override doDisconnect(conn: NativeDocStorage) {
|
||||
conn
|
||||
.close()
|
||||
.then(() => {
|
||||
console.info('[nbstore] connection closed', this.shareId);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('[nbstore] connection close failed', this.shareId, err);
|
||||
});
|
||||
}
|
||||
}
|
||||
144
packages/frontend/apps/ios/src/plugins/nbstore/definitions.ts
Normal file
144
packages/frontend/apps/ios/src/plugins/nbstore/definitions.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
export interface Blob {
|
||||
key: string;
|
||||
// base64 encoded data
|
||||
data: string;
|
||||
mime: string;
|
||||
size: number;
|
||||
createdAt: number;
|
||||
}
|
||||
|
||||
export interface SetBlob {
|
||||
key: string;
|
||||
// base64 encoded data
|
||||
data: string;
|
||||
mime: string;
|
||||
}
|
||||
|
||||
export interface ListedBlob {
|
||||
key: string;
|
||||
mime: string;
|
||||
size: number;
|
||||
createdAt: number;
|
||||
}
|
||||
|
||||
export interface DocClock {
|
||||
docId: string;
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
export interface NbStorePlugin {
|
||||
getSpaceDBPath: (options: {
|
||||
peer: string;
|
||||
spaceType: string;
|
||||
id: string;
|
||||
}) => Promise<{ path: string }>;
|
||||
create: (options: { id: string; path: string }) => Promise<void>;
|
||||
connect: (options: { id: string }) => Promise<void>;
|
||||
close: (options: { id: string }) => Promise<void>;
|
||||
isClosed: (options: { id: string }) => Promise<{ isClosed: boolean }>;
|
||||
checkpoint: (options: { id: string }) => Promise<void>;
|
||||
validate: (options: { id: string }) => Promise<{ isValidate: boolean }>;
|
||||
|
||||
setSpaceId: (options: { id: string; spaceId: string }) => Promise<void>;
|
||||
pushUpdate: (options: {
|
||||
id: string;
|
||||
docId: string;
|
||||
data: string;
|
||||
}) => Promise<{ timestamp: number }>;
|
||||
getDocSnapshot: (options: { id: string; docId: string }) => Promise<
|
||||
| {
|
||||
docId: string;
|
||||
// base64 encoded data
|
||||
data: string;
|
||||
timestamp: number;
|
||||
}
|
||||
| undefined
|
||||
>;
|
||||
setDocSnapshot: (options: {
|
||||
id: string;
|
||||
docId: string;
|
||||
data: string;
|
||||
}) => Promise<{ success: boolean }>;
|
||||
getDocUpdates: (options: { id: string; docId: string }) => Promise<
|
||||
{
|
||||
docId: string;
|
||||
createdAt: number;
|
||||
// base64 encoded data
|
||||
data: string;
|
||||
}[]
|
||||
>;
|
||||
markUpdatesMerged: (options: {
|
||||
id: string;
|
||||
docId: string;
|
||||
timestamps: number[];
|
||||
}) => Promise<{ count: number }>;
|
||||
deleteDoc: (options: { id: string; docId: string }) => Promise<void>;
|
||||
getDocClocks: (options: { id: string; after: number }) => Promise<
|
||||
{
|
||||
docId: string;
|
||||
timestamp: number;
|
||||
}[]
|
||||
>;
|
||||
getDocClock: (options: { id: string; docId: string }) => Promise<
|
||||
| {
|
||||
docId: string;
|
||||
timestamp: number;
|
||||
}
|
||||
| undefined
|
||||
>;
|
||||
getBlob: (options: { id: string; key: string }) => Promise<Blob | null>;
|
||||
setBlob: (options: { id: string } & SetBlob) => Promise<void>;
|
||||
deleteBlob: (options: {
|
||||
id: string;
|
||||
key: string;
|
||||
permanently: boolean;
|
||||
}) => Promise<void>;
|
||||
releaseBlobs: (options: { id: string }) => Promise<void>;
|
||||
listBlobs: (options: { id: string }) => Promise<Array<ListedBlob>>;
|
||||
getPeerRemoteClocks: (options: {
|
||||
id: string;
|
||||
peer: string;
|
||||
}) => Promise<Array<DocClock>>;
|
||||
getPeerRemoteClock: (options: {
|
||||
id: string;
|
||||
peer: string;
|
||||
docId: string;
|
||||
}) => Promise<DocClock>;
|
||||
setPeerRemoteClock: (options: {
|
||||
id: string;
|
||||
peer: string;
|
||||
docId: string;
|
||||
clock: number;
|
||||
}) => Promise<void>;
|
||||
getPeerPushedClocks: (options: {
|
||||
id: string;
|
||||
peer: string;
|
||||
}) => Promise<Array<DocClock>>;
|
||||
getPeerPushedClock: (options: {
|
||||
id: string;
|
||||
peer: string;
|
||||
docId: string;
|
||||
}) => Promise<DocClock>;
|
||||
setPeerPushedClock: (options: {
|
||||
id: string;
|
||||
peer: string;
|
||||
docId: string;
|
||||
clock: number;
|
||||
}) => Promise<void>;
|
||||
getPeerPulledRemoteClocks: (options: {
|
||||
id: string;
|
||||
peer: string;
|
||||
}) => Promise<Array<DocClock>>;
|
||||
getPeerPulledRemoteClock: (options: {
|
||||
id: string;
|
||||
peer: string;
|
||||
docId: string;
|
||||
}) => Promise<DocClock>;
|
||||
setPeerPulledRemoteClock: (options: {
|
||||
id: string;
|
||||
peer: string;
|
||||
docId: string;
|
||||
clock: number;
|
||||
}) => Promise<void>;
|
||||
clearClocks: (options: { id: string }) => Promise<void>;
|
||||
}
|
||||
83
packages/frontend/apps/ios/src/plugins/nbstore/doc.ts
Normal file
83
packages/frontend/apps/ios/src/plugins/nbstore/doc.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import {
|
||||
type DocClocks,
|
||||
type DocRecord,
|
||||
DocStorageBase,
|
||||
type DocUpdate,
|
||||
share,
|
||||
} from '@affine/nbstore';
|
||||
|
||||
import { NativeDBConnection } from './db';
|
||||
|
||||
export class SqliteDocStorage extends DocStorageBase {
|
||||
override connection = share(
|
||||
new NativeDBConnection(this.peer, this.spaceType, this.spaceId)
|
||||
);
|
||||
|
||||
get db() {
|
||||
return this.connection.inner;
|
||||
}
|
||||
|
||||
override async pushDocUpdate(update: DocUpdate) {
|
||||
const timestamp = await this.db.pushUpdate(update.docId, update.bin);
|
||||
|
||||
return { docId: update.docId, timestamp };
|
||||
}
|
||||
|
||||
override async deleteDoc(docId: string) {
|
||||
await this.db.deleteDoc(docId);
|
||||
}
|
||||
|
||||
override async getDocTimestamps(after?: Date) {
|
||||
const clocks = await this.db.getDocClocks(after);
|
||||
|
||||
return clocks.reduce((ret, cur) => {
|
||||
ret[cur.docId] = cur.timestamp;
|
||||
return ret;
|
||||
}, {} as DocClocks);
|
||||
}
|
||||
|
||||
override async getDocTimestamp(docId: string) {
|
||||
return this.db.getDocClock(docId);
|
||||
}
|
||||
|
||||
protected override async getDocSnapshot(docId: string) {
|
||||
const snapshot = await this.db.getDocSnapshot(docId);
|
||||
|
||||
if (!snapshot) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
docId,
|
||||
bin: snapshot.data,
|
||||
timestamp: snapshot.timestamp,
|
||||
};
|
||||
}
|
||||
|
||||
protected override async setDocSnapshot(
|
||||
snapshot: DocRecord
|
||||
): Promise<boolean> {
|
||||
return this.db.setDocSnapshot({
|
||||
docId: snapshot.docId,
|
||||
data: Buffer.from(snapshot.bin),
|
||||
timestamp: new Date(snapshot.timestamp),
|
||||
});
|
||||
}
|
||||
|
||||
protected override async getDocUpdates(docId: string) {
|
||||
return this.db.getDocUpdates(docId).then(updates =>
|
||||
updates.map(update => ({
|
||||
docId,
|
||||
bin: update.data,
|
||||
timestamp: update.createdAt,
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
protected override markUpdatesMerged(docId: string, updates: DocRecord[]) {
|
||||
return this.db.markUpdatesMerged(
|
||||
docId,
|
||||
updates.map(update => update.timestamp)
|
||||
);
|
||||
}
|
||||
}
|
||||
128
packages/frontend/apps/ios/src/plugins/nbstore/handlers.ts
Normal file
128
packages/frontend/apps/ios/src/plugins/nbstore/handlers.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
import {
|
||||
type BlobRecord,
|
||||
type DocClock,
|
||||
type DocUpdate,
|
||||
} from '@affine/nbstore';
|
||||
|
||||
import { ensureStorage, getStorage } from './storage';
|
||||
|
||||
export const nbstoreHandlers = {
|
||||
connect: async (id: string) => {
|
||||
await ensureStorage(id);
|
||||
},
|
||||
|
||||
close: async (id: string) => {
|
||||
const store = getStorage(id);
|
||||
|
||||
if (store) {
|
||||
store.disconnect();
|
||||
// The store may be shared with other tabs, so we don't delete it from cache
|
||||
// the underlying connection will handle the close correctly
|
||||
// STORE_CACHE.delete(`${spaceType}:${spaceId}`);
|
||||
}
|
||||
},
|
||||
|
||||
pushDocUpdate: async (id: string, update: DocUpdate) => {
|
||||
const store = await ensureStorage(id);
|
||||
return store.get('doc').pushDocUpdate(update);
|
||||
},
|
||||
|
||||
getDoc: async (id: string, docId: string) => {
|
||||
const store = await ensureStorage(id);
|
||||
return store.get('doc').getDoc(docId);
|
||||
},
|
||||
|
||||
deleteDoc: async (id: string, docId: string) => {
|
||||
const store = await ensureStorage(id);
|
||||
return store.get('doc').deleteDoc(docId);
|
||||
},
|
||||
|
||||
getDocTimestamps: async (id: string, after?: Date) => {
|
||||
const store = await ensureStorage(id);
|
||||
return store.get('doc').getDocTimestamps(after);
|
||||
},
|
||||
|
||||
getDocTimestamp: async (id: string, docId: string) => {
|
||||
const store = await ensureStorage(id);
|
||||
return store.get('doc').getDocTimestamp(docId);
|
||||
},
|
||||
|
||||
setBlob: async (id: string, blob: BlobRecord) => {
|
||||
const store = await ensureStorage(id);
|
||||
return store.get('blob').set(blob);
|
||||
},
|
||||
|
||||
getBlob: async (id: string, key: string) => {
|
||||
const store = await ensureStorage(id);
|
||||
return store.get('blob').get(key);
|
||||
},
|
||||
|
||||
deleteBlob: async (id: string, key: string, permanently: boolean) => {
|
||||
const store = await ensureStorage(id);
|
||||
return store.get('blob').delete(key, permanently);
|
||||
},
|
||||
|
||||
listBlobs: async (id: string) => {
|
||||
const store = await ensureStorage(id);
|
||||
return store.get('blob').list();
|
||||
},
|
||||
|
||||
releaseBlobs: async (id: string) => {
|
||||
const store = await ensureStorage(id);
|
||||
return store.get('blob').release();
|
||||
},
|
||||
|
||||
getPeerRemoteClocks: async (id: string, peer: string) => {
|
||||
const store = await ensureStorage(id);
|
||||
return store.get('sync').getPeerRemoteClocks(peer);
|
||||
},
|
||||
|
||||
getPeerRemoteClock: async (id: string, peer: string, docId: string) => {
|
||||
const store = await ensureStorage(id);
|
||||
return store.get('sync').getPeerRemoteClock(peer, docId);
|
||||
},
|
||||
|
||||
setPeerRemoteClock: async (id: string, peer: string, clock: DocClock) => {
|
||||
const store = await ensureStorage(id);
|
||||
return store.get('sync').setPeerRemoteClock(peer, clock);
|
||||
},
|
||||
|
||||
getPeerPulledRemoteClocks: async (id: string, peer: string) => {
|
||||
const store = await ensureStorage(id);
|
||||
return store.get('sync').getPeerPulledRemoteClocks(peer);
|
||||
},
|
||||
|
||||
getPeerPulledRemoteClock: async (id: string, peer: string, docId: string) => {
|
||||
const store = await ensureStorage(id);
|
||||
return store.get('sync').getPeerPulledRemoteClock(peer, docId);
|
||||
},
|
||||
|
||||
setPeerPulledRemoteClock: async (
|
||||
id: string,
|
||||
peer: string,
|
||||
clock: DocClock
|
||||
) => {
|
||||
const store = await ensureStorage(id);
|
||||
return store.get('sync').setPeerPulledRemoteClock(peer, clock);
|
||||
},
|
||||
|
||||
getPeerPushedClocks: async (id: string, peer: string) => {
|
||||
const store = await ensureStorage(id);
|
||||
return store.get('sync').getPeerPushedClocks(peer);
|
||||
},
|
||||
|
||||
getPeerPushedClock: async (id: string, peer: string, docId: string) => {
|
||||
const store = await ensureStorage(id);
|
||||
return store.get('sync').getPeerPushedClock(peer, docId);
|
||||
},
|
||||
|
||||
setPeerPushedClock: async (id: string, peer: string, clock: DocClock) => {
|
||||
const store = await ensureStorage(id);
|
||||
return store.get('sync').setPeerPushedClock(peer, clock);
|
||||
},
|
||||
|
||||
clearClocks: async (id: string) => {
|
||||
const store = await ensureStorage(id);
|
||||
return store.get('sync').clearClocks();
|
||||
},
|
||||
};
|
||||
5
packages/frontend/apps/ios/src/plugins/nbstore/index.ts
Normal file
5
packages/frontend/apps/ios/src/plugins/nbstore/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export * from './definitions';
|
||||
export { nbstoreHandlers } from './handlers';
|
||||
export { NbStoreDocStorage } from './plugin';
|
||||
export * from './storage';
|
||||
export { universalId } from '@affine/nbstore';
|
||||
312
packages/frontend/apps/ios/src/plugins/nbstore/plugin.ts
Normal file
312
packages/frontend/apps/ios/src/plugins/nbstore/plugin.ts
Normal file
@@ -0,0 +1,312 @@
|
||||
import {
|
||||
base64ToUint8Array,
|
||||
uint8ArrayToBase64,
|
||||
} from '@affine/core/modules/workspace-engine';
|
||||
import {
|
||||
type Blob,
|
||||
type DocClock,
|
||||
type DocRecord,
|
||||
type DocStorage,
|
||||
type DocUpdate,
|
||||
type ListedBlob,
|
||||
} from '@affine/native';
|
||||
import { registerPlugin } from '@capacitor/core';
|
||||
|
||||
import type { NbStorePlugin } from './definitions';
|
||||
|
||||
export const NbStoreDocStorage =
|
||||
registerPlugin<NbStorePlugin>('NbStoreDocStorage');
|
||||
|
||||
export interface SetBlob {
|
||||
key: string;
|
||||
data: Uint8Array;
|
||||
mime: string;
|
||||
}
|
||||
|
||||
export class NativeDocStorage implements DocStorage {
|
||||
constructor(private readonly universalId: string) {}
|
||||
|
||||
/** Initialize the database and run migrations. */
|
||||
connect(): Promise<void> {
|
||||
return NbStoreDocStorage.connect({
|
||||
id: this.universalId,
|
||||
});
|
||||
}
|
||||
|
||||
close(): Promise<void> {
|
||||
return NbStoreDocStorage.close({
|
||||
id: this.universalId,
|
||||
});
|
||||
}
|
||||
|
||||
get isClosed(): Promise<boolean> {
|
||||
return NbStoreDocStorage.isClosed({
|
||||
id: this.universalId,
|
||||
}).then(result => result.isClosed);
|
||||
}
|
||||
/**
|
||||
* Flush the WAL file to the database file.
|
||||
* See https://www.sqlite.org/pragma.html#pragma_wal_checkpoint:~:text=PRAGMA%20schema.wal_checkpoint%3B
|
||||
*/
|
||||
checkpoint(): Promise<void> {
|
||||
return NbStoreDocStorage.checkpoint({
|
||||
id: this.universalId,
|
||||
});
|
||||
}
|
||||
|
||||
validate(): Promise<boolean> {
|
||||
return NbStoreDocStorage.validate({
|
||||
id: this.universalId,
|
||||
}).then(result => result.isValidate);
|
||||
}
|
||||
|
||||
setSpaceId(spaceId: string): Promise<void> {
|
||||
return NbStoreDocStorage.setSpaceId({
|
||||
id: this.universalId,
|
||||
spaceId,
|
||||
});
|
||||
}
|
||||
|
||||
async pushUpdate(docId: string, update: Uint8Array): Promise<Date> {
|
||||
return NbStoreDocStorage.pushUpdate({
|
||||
id: this.universalId,
|
||||
docId,
|
||||
data: await uint8ArrayToBase64(update),
|
||||
}).then(result => new Date(result.timestamp));
|
||||
}
|
||||
|
||||
getDocSnapshot(docId: string): Promise<DocRecord | null> {
|
||||
return NbStoreDocStorage.getDocSnapshot({
|
||||
id: this.universalId,
|
||||
docId,
|
||||
}).then(result => {
|
||||
if (result) {
|
||||
return {
|
||||
...result,
|
||||
data: base64ToUint8Array(result.data),
|
||||
timestamp: new Date(result.timestamp),
|
||||
};
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
async setDocSnapshot(snapshot: DocRecord): Promise<boolean> {
|
||||
return NbStoreDocStorage.setDocSnapshot({
|
||||
id: this.universalId,
|
||||
docId: snapshot.docId,
|
||||
data: await uint8ArrayToBase64(snapshot.data),
|
||||
}).then(result => result.success);
|
||||
}
|
||||
|
||||
getDocUpdates(docId: string): Promise<Array<DocUpdate>> {
|
||||
return NbStoreDocStorage.getDocUpdates({
|
||||
id: this.universalId,
|
||||
docId,
|
||||
}).then(result =>
|
||||
result.map(update => ({
|
||||
...update,
|
||||
data: base64ToUint8Array(update.data),
|
||||
createdAt: new Date(update.createdAt),
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
markUpdatesMerged(docId: string, updates: Array<Date>): Promise<number> {
|
||||
return NbStoreDocStorage.markUpdatesMerged({
|
||||
id: this.universalId,
|
||||
docId,
|
||||
timestamps: updates.map(date => date.getTime()),
|
||||
}).then(result => result.count);
|
||||
}
|
||||
|
||||
deleteDoc(docId: string): Promise<void> {
|
||||
return NbStoreDocStorage.deleteDoc({
|
||||
id: this.universalId,
|
||||
docId,
|
||||
});
|
||||
}
|
||||
|
||||
getDocClocks(after: Date): Promise<Array<DocClock>> {
|
||||
return NbStoreDocStorage.getDocClocks({
|
||||
id: this.universalId,
|
||||
after: after.getTime(),
|
||||
}).then(result =>
|
||||
result.map(clock => ({
|
||||
...clock,
|
||||
timestamp: new Date(clock.timestamp),
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
getDocClock(docId: string): Promise<DocClock | null> {
|
||||
return NbStoreDocStorage.getDocClock({
|
||||
id: this.universalId,
|
||||
docId,
|
||||
}).then(result => {
|
||||
if (result) {
|
||||
return {
|
||||
...result,
|
||||
timestamp: new Date(result.timestamp),
|
||||
};
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
getBlob(key: string): Promise<Blob | null> {
|
||||
return NbStoreDocStorage.getBlob({
|
||||
id: this.universalId,
|
||||
key,
|
||||
}).then(result => {
|
||||
if (result) {
|
||||
return {
|
||||
...result,
|
||||
data: base64ToUint8Array(result.data),
|
||||
createdAt: new Date(result.createdAt),
|
||||
};
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
async setBlob(blob: SetBlob): Promise<void> {
|
||||
return NbStoreDocStorage.setBlob({
|
||||
id: this.universalId,
|
||||
key: blob.key,
|
||||
data: await uint8ArrayToBase64(blob.data),
|
||||
mime: blob.mime,
|
||||
});
|
||||
}
|
||||
|
||||
deleteBlob(key: string, permanently: boolean): Promise<void> {
|
||||
return NbStoreDocStorage.deleteBlob({
|
||||
id: this.universalId,
|
||||
key,
|
||||
permanently,
|
||||
});
|
||||
}
|
||||
|
||||
releaseBlobs(): Promise<void> {
|
||||
return NbStoreDocStorage.releaseBlobs({
|
||||
id: this.universalId,
|
||||
});
|
||||
}
|
||||
|
||||
async listBlobs(): Promise<Array<ListedBlob>> {
|
||||
return (
|
||||
await NbStoreDocStorage.listBlobs({
|
||||
id: this.universalId,
|
||||
})
|
||||
).map(blob => ({
|
||||
...blob,
|
||||
createdAt: new Date(blob.createdAt),
|
||||
}));
|
||||
}
|
||||
|
||||
getPeerRemoteClocks(peer: string): Promise<Array<DocClock>> {
|
||||
return NbStoreDocStorage.getPeerRemoteClocks({
|
||||
id: this.universalId,
|
||||
peer,
|
||||
}).then(result =>
|
||||
result.map(clock => ({
|
||||
...clock,
|
||||
timestamp: new Date(clock.timestamp),
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
getPeerRemoteClock(peer: string, docId: string): Promise<DocClock> {
|
||||
return NbStoreDocStorage.getPeerRemoteClock({
|
||||
id: this.universalId,
|
||||
peer,
|
||||
docId,
|
||||
}).then(result => ({
|
||||
...result,
|
||||
timestamp: new Date(result.timestamp),
|
||||
}));
|
||||
}
|
||||
|
||||
setPeerRemoteClock(peer: string, docId: string, clock: Date): Promise<void> {
|
||||
return NbStoreDocStorage.setPeerRemoteClock({
|
||||
id: this.universalId,
|
||||
peer,
|
||||
docId,
|
||||
clock: clock.getTime(),
|
||||
});
|
||||
}
|
||||
|
||||
getPeerPulledRemoteClocks(peer: string): Promise<Array<DocClock>> {
|
||||
return NbStoreDocStorage.getPeerPulledRemoteClocks({
|
||||
id: this.universalId,
|
||||
peer,
|
||||
}).then(result =>
|
||||
result.map(clock => ({
|
||||
...clock,
|
||||
timestamp: new Date(clock.timestamp),
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
getPeerPulledRemoteClock(peer: string, docId: string): Promise<DocClock> {
|
||||
return NbStoreDocStorage.getPeerPulledRemoteClock({
|
||||
id: this.universalId,
|
||||
peer,
|
||||
docId,
|
||||
}).then(result => ({
|
||||
...result,
|
||||
timestamp: new Date(result.timestamp),
|
||||
}));
|
||||
}
|
||||
|
||||
setPeerPulledRemoteClock(
|
||||
peer: string,
|
||||
docId: string,
|
||||
clock: Date
|
||||
): Promise<void> {
|
||||
return NbStoreDocStorage.setPeerPulledRemoteClock({
|
||||
id: this.universalId,
|
||||
peer,
|
||||
docId,
|
||||
clock: clock.getTime(),
|
||||
});
|
||||
}
|
||||
|
||||
getPeerPushedClocks(peer: string): Promise<Array<DocClock>> {
|
||||
return NbStoreDocStorage.getPeerPushedClocks({
|
||||
id: this.universalId,
|
||||
peer,
|
||||
}).then(result =>
|
||||
result.map(clock => ({
|
||||
...clock,
|
||||
timestamp: new Date(clock.timestamp),
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
getPeerPushedClock(peer: string, docId: string): Promise<DocClock> {
|
||||
return NbStoreDocStorage.getPeerPushedClock({
|
||||
id: this.universalId,
|
||||
peer,
|
||||
docId,
|
||||
}).then(result => ({
|
||||
...result,
|
||||
timestamp: new Date(result.timestamp),
|
||||
}));
|
||||
}
|
||||
|
||||
setPeerPushedClock(peer: string, docId: string, clock: Date): Promise<void> {
|
||||
return NbStoreDocStorage.setPeerPushedClock({
|
||||
id: this.universalId,
|
||||
peer,
|
||||
docId,
|
||||
clock: clock.getTime(),
|
||||
});
|
||||
}
|
||||
|
||||
clearClocks(): Promise<void> {
|
||||
return NbStoreDocStorage.clearClocks({
|
||||
id: this.universalId,
|
||||
});
|
||||
}
|
||||
}
|
||||
83
packages/frontend/apps/ios/src/plugins/nbstore/storage.ts
Normal file
83
packages/frontend/apps/ios/src/plugins/nbstore/storage.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { parseUniversalId, SpaceStorage } from '@affine/nbstore';
|
||||
import { applyUpdate, Doc as YDoc } from 'yjs';
|
||||
|
||||
import { SqliteBlobStorage } from './blob';
|
||||
import { NativeDBConnection } from './db';
|
||||
import { SqliteDocStorage } from './doc';
|
||||
import { SqliteSyncStorage } from './sync';
|
||||
|
||||
export class SqliteSpaceStorage extends SpaceStorage {
|
||||
get connection() {
|
||||
const docStore = this.get('doc');
|
||||
|
||||
if (!docStore) {
|
||||
throw new Error('doc store not found');
|
||||
}
|
||||
|
||||
const connection = docStore.connection;
|
||||
|
||||
if (!(connection instanceof NativeDBConnection)) {
|
||||
throw new Error('doc store connection is not a Sqlite connection');
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
async getDBPath() {
|
||||
return this.connection.getDBPath();
|
||||
}
|
||||
|
||||
async getWorkspaceName() {
|
||||
const docStore = this.tryGet('doc');
|
||||
|
||||
if (!docStore) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const doc = await docStore.getDoc(docStore.spaceId);
|
||||
if (!doc) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const ydoc = new YDoc();
|
||||
applyUpdate(ydoc, doc.bin);
|
||||
return ydoc.getMap('meta').get('name') as string;
|
||||
}
|
||||
|
||||
async checkpoint() {
|
||||
await this.connection.inner.checkpoint();
|
||||
}
|
||||
}
|
||||
|
||||
const STORE_CACHE = new Map<string, SqliteSpaceStorage>();
|
||||
|
||||
export function getStorage(universalId: string) {
|
||||
return STORE_CACHE.get(universalId);
|
||||
}
|
||||
|
||||
export async function ensureStorage(universalId: string) {
|
||||
const { peer, type, id } = parseUniversalId(universalId);
|
||||
let store = STORE_CACHE.get(universalId);
|
||||
|
||||
if (!store) {
|
||||
const opts = {
|
||||
peer,
|
||||
type,
|
||||
id,
|
||||
};
|
||||
|
||||
store = new SqliteSpaceStorage([
|
||||
new SqliteDocStorage(opts),
|
||||
new SqliteBlobStorage(opts),
|
||||
new SqliteSyncStorage(opts),
|
||||
]);
|
||||
|
||||
store.connect();
|
||||
|
||||
await store.waitForConnected();
|
||||
|
||||
STORE_CACHE.set(universalId, store);
|
||||
}
|
||||
|
||||
return store;
|
||||
}
|
||||
70
packages/frontend/apps/ios/src/plugins/nbstore/sync.ts
Normal file
70
packages/frontend/apps/ios/src/plugins/nbstore/sync.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import {
|
||||
BasicSyncStorage,
|
||||
type DocClock,
|
||||
type DocClocks,
|
||||
share,
|
||||
} from '@affine/nbstore';
|
||||
|
||||
import { NativeDBConnection } from './db';
|
||||
|
||||
export class SqliteSyncStorage extends BasicSyncStorage {
|
||||
override connection = share(
|
||||
new NativeDBConnection(this.peer, this.spaceType, this.spaceId)
|
||||
);
|
||||
|
||||
get db() {
|
||||
return this.connection.inner;
|
||||
}
|
||||
|
||||
override async getPeerRemoteClocks(peer: string) {
|
||||
const records = await this.db.getPeerRemoteClocks(peer);
|
||||
return records.reduce((clocks, { docId, timestamp }) => {
|
||||
clocks[docId] = timestamp;
|
||||
return clocks;
|
||||
}, {} as DocClocks);
|
||||
}
|
||||
|
||||
override async getPeerRemoteClock(peer: string, docId: string) {
|
||||
return this.db.getPeerRemoteClock(peer, docId);
|
||||
}
|
||||
|
||||
override async setPeerRemoteClock(peer: string, clock: DocClock) {
|
||||
await this.db.setPeerRemoteClock(peer, clock.docId, clock.timestamp);
|
||||
}
|
||||
|
||||
override async getPeerPulledRemoteClock(peer: string, docId: string) {
|
||||
return this.db.getPeerPulledRemoteClock(peer, docId);
|
||||
}
|
||||
|
||||
override async getPeerPulledRemoteClocks(peer: string) {
|
||||
const records = await this.db.getPeerPulledRemoteClocks(peer);
|
||||
return records.reduce((clocks, { docId, timestamp }) => {
|
||||
clocks[docId] = timestamp;
|
||||
return clocks;
|
||||
}, {} as DocClocks);
|
||||
}
|
||||
|
||||
override async setPeerPulledRemoteClock(peer: string, clock: DocClock) {
|
||||
await this.db.setPeerPulledRemoteClock(peer, clock.docId, clock.timestamp);
|
||||
}
|
||||
|
||||
override async getPeerPushedClocks(peer: string) {
|
||||
const records = await this.db.getPeerPushedClocks(peer);
|
||||
return records.reduce((clocks, { docId, timestamp }) => {
|
||||
clocks[docId] = timestamp;
|
||||
return clocks;
|
||||
}, {} as DocClocks);
|
||||
}
|
||||
|
||||
override async getPeerPushedClock(peer: string, docId: string) {
|
||||
return this.db.getPeerPushedClock(peer, docId);
|
||||
}
|
||||
|
||||
override async setPeerPushedClock(peer: string, clock: DocClock) {
|
||||
await this.db.setPeerPushedClock(peer, clock.docId, clock.timestamp);
|
||||
}
|
||||
|
||||
override async clearClocks() {
|
||||
await this.db.clearClocks();
|
||||
}
|
||||
}
|
||||
@@ -8,5 +8,9 @@
|
||||
"rootDir": "./src"
|
||||
},
|
||||
"include": ["./src"],
|
||||
"references": [{ "path": "../../core" }]
|
||||
"references": [
|
||||
{ "path": "../../core" },
|
||||
{ "path": "../../native" },
|
||||
{ "path": "../../../common/nbstore" }
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,4 +2,4 @@ export {
|
||||
type ElementOrFactory,
|
||||
useLitPortal,
|
||||
useLitPortalFactory,
|
||||
} from './lite-portal';
|
||||
} from './lit-portal';
|
||||
|
||||
@@ -7,16 +7,14 @@ import ReactDOM from 'react-dom';
|
||||
type PortalEvent = {
|
||||
name: 'connectedCallback' | 'disconnectedCallback' | 'willUpdate';
|
||||
target: LitReactPortal;
|
||||
previousPortalId?: string;
|
||||
};
|
||||
|
||||
type PortalListener = (event: PortalEvent) => void;
|
||||
|
||||
export function createLitPortalAnchor(callback: (event: PortalEvent) => void) {
|
||||
const id = nanoid();
|
||||
function createLitPortalAnchor(callback: (event: PortalEvent) => void) {
|
||||
return html`<lit-react-portal
|
||||
.notify=${callback}
|
||||
portalId=${id}
|
||||
portalId=${nanoid()}
|
||||
></lit-react-portal>`;
|
||||
}
|
||||
|
||||
@@ -25,7 +23,6 @@ export const LIT_REACT_PORTAL = 'lit-react-portal';
|
||||
@customElement(LIT_REACT_PORTAL)
|
||||
class LitReactPortal extends LitElement {
|
||||
portalId!: string;
|
||||
|
||||
notify!: PortalListener;
|
||||
|
||||
static override get properties() {
|
||||
@@ -35,6 +32,14 @@ class LitReactPortal extends LitElement {
|
||||
};
|
||||
}
|
||||
|
||||
override connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this.notify({
|
||||
name: 'connectedCallback',
|
||||
target: this,
|
||||
});
|
||||
}
|
||||
|
||||
override attributeChangedCallback(
|
||||
name: string,
|
||||
oldVal: string,
|
||||
@@ -45,7 +50,6 @@ class LitReactPortal extends LitElement {
|
||||
this.notify({
|
||||
name: 'willUpdate',
|
||||
target: this,
|
||||
previousPortalId: oldVal,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -55,13 +59,6 @@ class LitReactPortal extends LitElement {
|
||||
return this;
|
||||
}
|
||||
|
||||
override connectedCallback() {
|
||||
this.notify({
|
||||
name: 'connectedCallback',
|
||||
target: this,
|
||||
});
|
||||
}
|
||||
|
||||
override disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
this.notify({
|
||||
@@ -82,6 +79,7 @@ export type ElementOrFactory = React.ReactElement | (() => React.ReactElement);
|
||||
type LitPortal = {
|
||||
id: string;
|
||||
portal: React.ReactPortal;
|
||||
litElement: LitReactPortal;
|
||||
};
|
||||
|
||||
// returns a factory function that renders a given element to a lit template
|
||||
@@ -99,45 +97,37 @@ export const useLitPortalFactory = () => {
|
||||
? elementOrFactory()
|
||||
: elementOrFactory;
|
||||
return createLitPortalAnchor(event => {
|
||||
const { name, target } = event;
|
||||
const id = target.portalId;
|
||||
|
||||
if (name === 'connectedCallback') {
|
||||
setPortals(portals => [
|
||||
...portals,
|
||||
{
|
||||
id,
|
||||
portal: ReactDOM.createPortal(element, target, id),
|
||||
},
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (name === 'disconnectedCallback') {
|
||||
setPortals(portals => portals.filter(p => p.id !== id));
|
||||
return;
|
||||
}
|
||||
|
||||
const prevId = event.previousPortalId;
|
||||
// Ignore first `willUpdate`
|
||||
if (!prevId) {
|
||||
return;
|
||||
}
|
||||
|
||||
// No re-rendering allowed
|
||||
// Used in `pdf embed view` scenario
|
||||
if (!rerendering) {
|
||||
return;
|
||||
}
|
||||
|
||||
setPortals(portals => {
|
||||
const portal = portals.find(p => p.id === prevId);
|
||||
if (!portal) return portals;
|
||||
|
||||
portal.id = id;
|
||||
portal.portal.key = id;
|
||||
portal.portal.children = element;
|
||||
return [...portals];
|
||||
const { name, target } = event;
|
||||
const id = target.portalId;
|
||||
let newPortals = portals;
|
||||
const updatePortals = () => {
|
||||
let oldPortalIndex = portals.findIndex(
|
||||
p => p.litElement === target
|
||||
);
|
||||
oldPortalIndex =
|
||||
oldPortalIndex === -1 ? portals.length : oldPortalIndex;
|
||||
newPortals = portals.toSpliced(oldPortalIndex, 1, {
|
||||
id,
|
||||
portal: ReactDOM.createPortal(element, target),
|
||||
litElement: target,
|
||||
});
|
||||
};
|
||||
switch (name) {
|
||||
case 'connectedCallback':
|
||||
updatePortals();
|
||||
break;
|
||||
case 'disconnectedCallback':
|
||||
newPortals = portals.filter(p => p.litElement.isConnected);
|
||||
break;
|
||||
case 'willUpdate':
|
||||
if (!target.isConnected || !rerendering) {
|
||||
break;
|
||||
}
|
||||
updatePortals();
|
||||
break;
|
||||
}
|
||||
return newPortals;
|
||||
});
|
||||
});
|
||||
},
|
||||
@@ -7,7 +7,6 @@ import type {
|
||||
EdgelessRootService,
|
||||
MindmapElementModel,
|
||||
ShapeElementModel,
|
||||
SurfaceBlockModel,
|
||||
} from '@blocksuite/affine/blocks';
|
||||
import {
|
||||
addImages,
|
||||
@@ -17,6 +16,7 @@ import {
|
||||
EDGELESS_TEXT_BLOCK_MIN_WIDTH,
|
||||
EdgelessTextBlockModel,
|
||||
fitContent,
|
||||
getSurfaceBlock,
|
||||
ImageBlockModel,
|
||||
InsertBelowIcon,
|
||||
LightLoadingIcon,
|
||||
@@ -363,9 +363,8 @@ function responseToCreateImage(host: EditorHost) {
|
||||
}
|
||||
|
||||
export function responseToExpandMindmap(host: EditorHost, ctx: AIContext) {
|
||||
const [surface] = host.doc.getBlockByFlavour(
|
||||
'affine:surface'
|
||||
) as SurfaceBlockModel[];
|
||||
const surface = getSurfaceBlock(host.doc);
|
||||
if (!surface) return;
|
||||
|
||||
const elements = ctx.get().selectedElements;
|
||||
const mindmapNode = ctx.get().node;
|
||||
@@ -414,9 +413,8 @@ function responseToBrainstormMindmap(host: EditorHost, ctx: AIContext) {
|
||||
const edgelessService = getEdgelessService(host);
|
||||
const edgelessCopilot = getEdgelessCopilotWidget(host);
|
||||
const selectionRect = edgelessCopilot.selectionModelRect;
|
||||
const [surface] = host.doc.getBlockByFlavour(
|
||||
'affine:surface'
|
||||
) as SurfaceBlockModel[];
|
||||
const surface = getSurfaceBlock(host.doc);
|
||||
if (!surface) return;
|
||||
|
||||
const { node, style, selectedElements } = ctx.get();
|
||||
if (!node) return;
|
||||
@@ -478,9 +476,8 @@ function responseToMakeItReal(host: EditorHost, ctx: AIContext) {
|
||||
html = preprocessHtml(html);
|
||||
|
||||
const edgelessCopilot = getEdgelessCopilotWidget(host);
|
||||
const [surface] = host.doc.getBlockByFlavour(
|
||||
'affine:surface'
|
||||
) as SurfaceBlockModel[];
|
||||
const surface = getSurfaceBlock(host.doc);
|
||||
if (!surface) return;
|
||||
|
||||
const data = ctx.get();
|
||||
const bounds = edgelessCopilot.determineInsertionBounds(
|
||||
|
||||
@@ -219,6 +219,7 @@ export function PDFViewerEmbeddedInner({ model }: PDFViewerProps) {
|
||||
icon={<ArrowUpSmallIcon />}
|
||||
className={embeddedStyles.pdfControlButton}
|
||||
onDoubleClick={stopPropagation}
|
||||
aria-label="Prev"
|
||||
{...navigator.prev}
|
||||
/>
|
||||
<IconButton
|
||||
@@ -226,6 +227,7 @@ export function PDFViewerEmbeddedInner({ model }: PDFViewerProps) {
|
||||
icon={<ArrowDownSmallIcon />}
|
||||
className={embeddedStyles.pdfControlButton}
|
||||
onDoubleClick={stopPropagation}
|
||||
aria-label="Next"
|
||||
{...navigator.next}
|
||||
/>
|
||||
<IconButton
|
||||
@@ -250,8 +252,13 @@ export function PDFViewerEmbeddedInner({ model }: PDFViewerProps) {
|
||||
embeddedStyles.pdfPageCount,
|
||||
])}
|
||||
>
|
||||
<span>{meta.pageCount > 0 ? cursor + 1 : '-'}</span>/
|
||||
<span>{meta.pageCount > 0 ? meta.pageCount : '-'}</span>
|
||||
<span className="page-cursor">
|
||||
{meta.pageCount > 0 ? cursor + 1 : '-'}
|
||||
</span>
|
||||
/
|
||||
<span className="page-count">
|
||||
{meta.pageCount > 0 ? meta.pageCount : '-'}
|
||||
</span>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { LoadingIcon } from '@affine/core/blocksuite/presets/blocks/_common/icon';
|
||||
import { fuzzyMatch } from '@affine/core/utils/fuzzy-match';
|
||||
import { I18n, i18nTime } from '@affine/i18n';
|
||||
import track from '@affine/track';
|
||||
@@ -11,6 +10,7 @@ import {
|
||||
LinkedWidgetUtils,
|
||||
} from '@blocksuite/affine/blocks';
|
||||
import { Text } from '@blocksuite/affine/store';
|
||||
import { createSignalFromObservable } from '@blocksuite/affine-shared/utils';
|
||||
import type { EditorHost } from '@blocksuite/block-std';
|
||||
import {
|
||||
DateTimeIcon,
|
||||
@@ -18,11 +18,12 @@ import {
|
||||
NewXxxPageIcon,
|
||||
} from '@blocksuite/icons/lit';
|
||||
import type { DocMeta } from '@blocksuite/store';
|
||||
import { signal } from '@preact/signals-core';
|
||||
import { computed } from '@preact/signals-core';
|
||||
import { Service } from '@toeverything/infra';
|
||||
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||
import { html } from 'lit';
|
||||
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
|
||||
import { map } from 'rxjs';
|
||||
|
||||
import type { WorkspaceDialogService } from '../../dialogs';
|
||||
import type { DocsService } from '../../doc';
|
||||
@@ -34,7 +35,6 @@ import type { RecentDocsService } from '../../quicksearch';
|
||||
import type { WorkspaceService } from '../../workspace';
|
||||
|
||||
const MAX_DOCS = 3;
|
||||
const LOAD_CHUNK = 100;
|
||||
export class AtMenuConfigService extends Service {
|
||||
constructor(
|
||||
private readonly workspaceService: WorkspaceService,
|
||||
@@ -75,7 +75,6 @@ export class AtMenuConfigService extends Service {
|
||||
const rawMetas = currentWorkspace.docCollection.meta.docMetas;
|
||||
const isJournal = (d: DocMeta) =>
|
||||
!!this.journalService.journalDate$(d.id).value;
|
||||
const docItems = signal<LinkedMenuItem[]>([]);
|
||||
|
||||
const docDisplayMetaService = this.docDisplayMetaService;
|
||||
|
||||
@@ -123,83 +122,94 @@ export class AtMenuConfigService extends Service {
|
||||
|
||||
const showRecent = query.trim().length === 0;
|
||||
|
||||
(async () => {
|
||||
const isIndexerLoading =
|
||||
this.docsSearch.indexer.status$.value.remaining !== undefined &&
|
||||
this.docsSearch.indexer.status$.value.remaining > 0;
|
||||
if (showRecent) {
|
||||
const recentDocs = this.recentDocsService.getRecentDocs();
|
||||
return {
|
||||
name: I18n.t('com.affine.editor.at-menu.recent-docs'),
|
||||
items: recentDocs
|
||||
.map(doc => {
|
||||
const meta = rawMetas.find(meta => meta.id === doc.id);
|
||||
if (!meta) {
|
||||
return null;
|
||||
}
|
||||
const item = toDocItem({
|
||||
...meta,
|
||||
highlights: undefined,
|
||||
});
|
||||
if (!item) {
|
||||
return null;
|
||||
}
|
||||
return item;
|
||||
})
|
||||
.filter(item => !!item),
|
||||
};
|
||||
} else {
|
||||
const { signal: docsSignal, cleanup } = createSignalFromObservable(
|
||||
this.searchDocs$(query).pipe(
|
||||
map(result => {
|
||||
const docs = result
|
||||
.map(doc => {
|
||||
const meta = rawMetas.find(meta => meta.id === doc.id);
|
||||
|
||||
if (!showRecent && isIndexerLoading) {
|
||||
// add a loading item
|
||||
docItems.value = [
|
||||
{
|
||||
key: 'loading',
|
||||
name: I18n.t('com.affine.editor.at-menu.loading'),
|
||||
icon: LoadingIcon,
|
||||
action: () => {
|
||||
// no action
|
||||
},
|
||||
},
|
||||
];
|
||||
// wait for indexer to finish
|
||||
await this.docsSearch.indexer.status$.waitFor(
|
||||
status => status.remaining === 0
|
||||
if (!meta) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const highlights =
|
||||
'highlights' in doc ? doc.highlights : undefined;
|
||||
|
||||
const docItem = toDocItem({
|
||||
...meta,
|
||||
highlights,
|
||||
});
|
||||
|
||||
if (!docItem) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return docItem;
|
||||
})
|
||||
.filter(m => !!m);
|
||||
|
||||
return docs;
|
||||
})
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
const { signal: isIndexerLoading, cleanup: cleanupIndexerLoading } =
|
||||
createSignalFromObservable(
|
||||
this.docsSearch.indexer.status$.pipe(
|
||||
map(
|
||||
status => status.remaining !== undefined && status.remaining > 0
|
||||
)
|
||||
),
|
||||
false
|
||||
);
|
||||
// remove the loading item
|
||||
docItems.value = [];
|
||||
}
|
||||
|
||||
const docMetas = (
|
||||
showRecent
|
||||
? this.recentDocsService.getRecentDocs()
|
||||
: await this.searchDocs(query)
|
||||
)
|
||||
.map(doc => {
|
||||
const meta = rawMetas.find(meta => meta.id === doc.id);
|
||||
|
||||
if (!meta) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const highlights = 'highlights' in doc ? doc.highlights : undefined;
|
||||
return {
|
||||
...meta,
|
||||
highlights,
|
||||
};
|
||||
})
|
||||
.filter((m): m is DocMetaWithHighlights => !!m);
|
||||
|
||||
for (const [index, meta] of docMetas.entries()) {
|
||||
if (abortSignal.aborted) {
|
||||
return;
|
||||
}
|
||||
|
||||
const item = toDocItem(meta);
|
||||
if (item) {
|
||||
docItems.value = [...docItems.value, item];
|
||||
}
|
||||
|
||||
if (index % LOAD_CHUNK === 0) {
|
||||
// use scheduler.yield?
|
||||
await new Promise(resolve => setTimeout(resolve, 0));
|
||||
}
|
||||
}
|
||||
})().catch(console.error);
|
||||
|
||||
return {
|
||||
name: showRecent
|
||||
? I18n.t('com.affine.editor.at-menu.recent-docs')
|
||||
: I18n.t('com.affine.editor.at-menu.link-to-doc', {
|
||||
query,
|
||||
}),
|
||||
items: docItems,
|
||||
maxDisplay: MAX_DOCS,
|
||||
get overflowText() {
|
||||
const overflowCount = docItems.value.length - MAX_DOCS;
|
||||
const overflowText = computed(() => {
|
||||
const overflowCount = docsSignal.value.length - MAX_DOCS;
|
||||
return I18n.t('com.affine.editor.at-menu.more-docs-hint', {
|
||||
count: overflowCount > 100 ? '100+' : overflowCount,
|
||||
});
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
abortSignal.addEventListener('abort', () => {
|
||||
cleanup();
|
||||
cleanupIndexerLoading();
|
||||
});
|
||||
|
||||
return {
|
||||
name: I18n.t('com.affine.editor.at-menu.link-to-doc', {
|
||||
query,
|
||||
}),
|
||||
loading: isIndexerLoading,
|
||||
loadingText: I18n.t('com.affine.editor.at-menu.loading'),
|
||||
items: docsSignal,
|
||||
maxDisplay: MAX_DOCS,
|
||||
overflowText,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private newDocMenuGroup(
|
||||
@@ -418,54 +428,58 @@ export class AtMenuConfigService extends Service {
|
||||
}
|
||||
|
||||
// only search docs by title, excluding blocks
|
||||
private async searchDocs(query: string) {
|
||||
const { buckets } = await this.docsSearch.indexer.blockIndex.aggregate(
|
||||
{
|
||||
type: 'boolean',
|
||||
occur: 'must',
|
||||
queries: [
|
||||
{
|
||||
type: 'match',
|
||||
field: 'content',
|
||||
match: query,
|
||||
},
|
||||
{
|
||||
type: 'boolean',
|
||||
occur: 'should',
|
||||
queries: [
|
||||
{
|
||||
type: 'match',
|
||||
field: 'flavour',
|
||||
match: 'affine:page',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
'docId',
|
||||
{
|
||||
hits: {
|
||||
fields: ['docId', 'content'],
|
||||
pagination: {
|
||||
limit: 1,
|
||||
},
|
||||
highlights: [
|
||||
private searchDocs$(query: string) {
|
||||
return this.docsSearch.indexer.blockIndex
|
||||
.aggregate$(
|
||||
{
|
||||
type: 'boolean',
|
||||
occur: 'must',
|
||||
queries: [
|
||||
{
|
||||
type: 'match',
|
||||
field: 'content',
|
||||
before: `<span style="color: ${cssVarV2('text/emphasis')}">`,
|
||||
end: '</span>',
|
||||
match: query,
|
||||
},
|
||||
{
|
||||
type: 'boolean',
|
||||
occur: 'should',
|
||||
queries: [
|
||||
{
|
||||
type: 'match',
|
||||
field: 'flavour',
|
||||
match: 'affine:page',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
);
|
||||
const result = buckets.map(bucket => {
|
||||
return {
|
||||
id: bucket.key,
|
||||
title: bucket.hits.nodes[0].fields.content,
|
||||
highlights: bucket.hits.nodes[0].highlights.content[0],
|
||||
};
|
||||
});
|
||||
return result;
|
||||
'docId',
|
||||
{
|
||||
hits: {
|
||||
fields: ['docId', 'content'],
|
||||
pagination: {
|
||||
limit: 1,
|
||||
},
|
||||
highlights: [
|
||||
{
|
||||
field: 'content',
|
||||
before: `<span style="color: ${cssVarV2('text/emphasis')}">`,
|
||||
end: '</span>',
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
)
|
||||
.pipe(
|
||||
map(({ buckets }) =>
|
||||
buckets.map(bucket => {
|
||||
return {
|
||||
id: bucket.key,
|
||||
title: bucket.hits.nodes[0].fields.content,
|
||||
highlights: bucket.hits.nodes[0].highlights.content[0],
|
||||
};
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,11 +30,11 @@ export const HighlightText = ({ text = '', end, start }: HighlightProps) => {
|
||||
|
||||
return (
|
||||
<span className={styles.highlightText}>
|
||||
{parts.map(part =>
|
||||
{parts.map((part, index) =>
|
||||
typeof part === 'string' ? (
|
||||
<Fragment key={part}>{part}</Fragment>
|
||||
) : (
|
||||
<span key={part.h} className={styles.highlightKeyword}>
|
||||
<span key={part.h + '.' + index} className={styles.highlightKeyword}>
|
||||
{part.h}
|
||||
</span>
|
||||
)
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
import { WorkspaceEngineStorageProvider } from './providers/engine';
|
||||
|
||||
export { CloudBlobStorage } from './impls/engine/blob-cloud';
|
||||
export { base64ToUint8Array, uint8ArrayToBase64 } from './utils/base64';
|
||||
|
||||
export function configureBrowserWorkspaceFlavours(framework: Framework) {
|
||||
framework
|
||||
|
||||
@@ -12,8 +12,22 @@ name = "uniffi-bindgen"
|
||||
path = "uniffi-bindgen.rs"
|
||||
|
||||
[dependencies]
|
||||
affine_common = { workspace = true }
|
||||
uniffi = { version = "0.28", features = ["cli"] }
|
||||
affine_common = { workspace = true }
|
||||
affine_nbstore = { workspace = true, features = ["use-as-lib"] }
|
||||
anyhow = { workspace = true }
|
||||
base64-simd = { workspace = true }
|
||||
chrono = { workspace = true }
|
||||
dashmap = { workspace = true }
|
||||
sqlx = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
uniffi = { workspace = true, features = ["cli"] }
|
||||
|
||||
[target.'cfg(any(target_os = "ios", target_os = "macos"))'.dependencies]
|
||||
objc2 = { workspace = true }
|
||||
objc2-foundation = { workspace = true, features = ["NSArray", "NSFileManager", "NSPathUtilities", "NSString", "NSURL"] }
|
||||
|
||||
[target.'cfg(not(any(target_os = "ios", target_os = "macos")))'.dependencies]
|
||||
homedir = { workspace = true }
|
||||
|
||||
[build-dependencies]
|
||||
uniffi = { version = "0.28", features = ["build"] }
|
||||
uniffi = { workspace = true, features = ["build"] }
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user