Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
name: Release

on:
push:
tags: ['v*']

permissions:
contents: read

jobs:
native:
strategy:
fail-fast: false
matrix:
include:
- platform: android
runner: ubuntu-latest
- platform: ios
runner: macos-15
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-js
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
workspaces: loro-rs
- name: Install Android targets
if: matrix.platform == 'android'
run: |
cargo install cargo-ndk --locked
rustup target add aarch64-linux-android armv7-linux-androideabi
- name: Install iOS targets
if: matrix.platform == 'ios'
run: rustup target add aarch64-apple-ios aarch64-apple-ios-sim x86_64-apple-ios
- name: Build native library and regenerate bindings
run: |
corepack yarn ubrn build ${{ matrix.platform }} --release --config ubrn.config.yaml --and-generate
bash scripts/add-extension.sh
- name: Collect Android files
if: matrix.platform == 'android'
run: tar -czf native-android.tgz android
- name: Collect iOS and generated binding files
if: matrix.platform == 'ios'
run: tar -czf native-ios.tgz build ios cpp src *.podspec
- uses: actions/upload-artifact@v4
with:
name: native-${{ matrix.platform }}
path: native-${{ matrix.platform }}.tgz
if-no-files-found: error
compression-level: 0

publish:
needs: native
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-js
- uses: actions/download-artifact@v4
with:
pattern: native-*
merge-multiple: true
- name: Assemble and check package
run: |
tar -xzf native-android.tgz
tar -xzf native-ios.tgz
corepack yarn typecheck
corepack yarn prepare
npm pack --ignore-scripts --json > pack.json
python3 scripts/verify-release.py "$(node -p "require('./pack.json')[0].filename")" "$GITHUB_REF_NAME"
- uses: actions/upload-artifact@v4
with:
name: npm-package
path: loro-react-native-*.tgz
if-no-files-found: error
- uses: actions/setup-node@v4
with:
node-version: 24
registry-url: https://registry.npmjs.org
- name: Publish verified tarball
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
npm install --global npm@11
npm publish "$(node -p "require('./pack.json')[0].filename")" --access public --provenance
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,18 @@ You can find an editor demo [here](https://github.com/Leeeon233/loro-react-nativ

## Dev

### Release 1.17.1

Uses Loro core and FFI 1.17.1, including `exportPendingUpdates()` for saving
received updates waiting for dependencies. Save these bytes with a consistent
snapshot and restore the snapshot first. Clear older saved pending bytes when
the method returns `undefined`.

Version tags run `.github/workflows/release.yml`: build release libraries for
iOS and Android, regenerate bindings, check TypeScript, and verify the npm
tarball contains both platforms before publishing. npm publishing requires a
trusted publisher for that workflow or the repository's `NPM_TOKEN` secret.

Follow the [getting started](https://jhugman.github.io/uniffi-bindgen-react-native/guides/pre-installation.html) to set up the environment.

### IOS
Expand Down Expand Up @@ -64,4 +76,3 @@ MIT
---

Made with [uniffi-bindgen-react-native](https://github.com/jhugman/uniffi-bindgen-react-native)

22 changes: 11 additions & 11 deletions loro-rs/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions loro-rs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "loro-rs"
version = "1.13.2"
version = "1.17.1"
edition = "2021"

[lib]
Expand All @@ -11,7 +11,7 @@ name = "uniffi-bindgen"
path = "src/uniffi-bindgen.rs"

[dependencies]
loro-ffi = { version = "1.13.7" }
loro-ffi = { version = "1.17.1" }
uniffi = { version = "0.31.1" }

[build-dependencies]
Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "loro-react-native",
"version": "1.13.2",
"version": "1.17.1",
"description": "React native binding for Loro",
"main": "./lib/module/index.js",
"types": "./lib/typescript/src/index.d.ts",
Expand Down Expand Up @@ -54,14 +54,14 @@
],
"repository": {
"type": "git",
"url": "git+https://github.com/Leeeon233/loro-react-native.git"
"url": "git+https://github.com/loro-dev/loro-react-native.git"
},
"author": "Leon Zhao <lz@loro.dev> (https://github.com/Leeeon233)",
"license": "MIT",
"bugs": {
"url": "https://github.com/Leeeon233/loro-react-native/issues"
"url": "https://github.com/loro-dev/loro-react-native/issues"
},
"homepage": "https://github.com/Leeeon233/loro-react-native#readme",
"homepage": "https://github.com/loro-dev/loro-react-native#readme",
"publishConfig": {
"registry": "https://registry.npmjs.org/"
},
Expand Down
40 changes: 40 additions & 0 deletions scripts/verify-release.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env python3
"""Reject a release tarball missing either platform's native libraries."""

import json
from pathlib import Path
import sys
import tarfile
import tomllib


def main():
tarball, tag = sys.argv[1:]
with tarfile.open(tarball, "r:gz") as archive:
names = set(archive.getnames())
package = json.load(archive.extractfile("package/package.json"))
assert tag == "v" + package["version"], "tag and package version differ"
required = {
"package/build/LoroFfiFramework.xcframework/Info.plist",
"package/android/src/main/jniLibs/arm64-v8a/libloro_rs.a",
"package/android/src/main/jniLibs/armeabi-v7a/libloro_rs.a",
"package/cpp/generated/loro.cpp",
"package/cpp/generated/loro.hpp",
"package/src/generated/loro.ts",
"package/LoroReactNative.podspec",
"package/" + package["main"].removeprefix("./"),
"package/" + package["types"].removeprefix("./"),
}
missing = required - names
assert not missing, "missing release files: " + ", ".join(sorted(missing))
bindings = archive.extractfile("package/src/generated/loro.ts").read()
assert b"exportPendingUpdates(" in bindings, "pending-update API missing"
lock = tomllib.loads(Path("loro-rs/Cargo.lock").read_text())
for name in ("loro", "loro-ffi", "loro-internal"):
versions = {p["version"] for p in lock["package"] if p["name"] == name}
assert versions == {package["version"]}, f"unexpected {name} versions: {versions}"
print(f"Verified {package['name']} {package['version']} with iOS and Android libraries.")


if __name__ == "__main__":
main()
2 changes: 1 addition & 1 deletion src/NativeLoroReactNative.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ export interface Spec extends TurboModule {
cleanupRustCrate(): boolean;
}

export default TurboModuleRegistry.getEnforcing<Spec>('LoroReactNative');
export default TurboModuleRegistry.getEnforcing<Spec>('LoroReactNative');
19 changes: 19 additions & 0 deletions src/generated/loro-ffi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,10 @@ interface NativeModuleInterface {
endVv: bigint,
uniffi_out_err: UniffiRustCallStatus
): Uint8Array;
ubrn_uniffi_loro_ffi_fn_method_lorodoc_export_pending_updates(
ptr: bigint,
uniffi_out_err: UniffiRustCallStatus
): Uint8Array;
ubrn_uniffi_loro_ffi_fn_method_lorodoc_export_shallow_snapshot(
ptr: bigint,
frontiers: bigint,
Expand Down Expand Up @@ -870,6 +874,18 @@ interface NativeModuleInterface {
f: bigint,
uniffi_out_err: UniffiRustCallStatus
): void;
ubrn_uniffi_loro_ffi_fn_method_lorodoc_try_export_json_updates(
ptr: bigint,
startVv: bigint,
endVv: bigint,
uniffi_out_err: UniffiRustCallStatus
): Uint8Array;
ubrn_uniffi_loro_ffi_fn_method_lorodoc_try_export_json_updates_without_peer_compression(
ptr: bigint,
startVv: bigint,
endVv: bigint,
uniffi_out_err: UniffiRustCallStatus
): Uint8Array;
ubrn_uniffi_loro_ffi_fn_method_lorodoc_try_get_counter(
ptr: bigint,
id: bigint,
Expand Down Expand Up @@ -2315,6 +2331,7 @@ interface NativeModuleInterface {
ubrn_uniffi_loro_ffi_checksum_method_lorodoc_export_json_in_id_span(): number;
ubrn_uniffi_loro_ffi_checksum_method_lorodoc_export_json_updates(): number;
ubrn_uniffi_loro_ffi_checksum_method_lorodoc_export_json_updates_without_peer_compression(): number;
ubrn_uniffi_loro_ffi_checksum_method_lorodoc_export_pending_updates(): number;
ubrn_uniffi_loro_ffi_checksum_method_lorodoc_export_shallow_snapshot(): number;
ubrn_uniffi_loro_ffi_checksum_method_lorodoc_export_snapshot(): number;
ubrn_uniffi_loro_ffi_checksum_method_lorodoc_export_snapshot_at(): number;
Expand Down Expand Up @@ -2379,6 +2396,8 @@ interface NativeModuleInterface {
ubrn_uniffi_loro_ffi_checksum_method_lorodoc_subscribe_pre_commit(): number;
ubrn_uniffi_loro_ffi_checksum_method_lorodoc_subscribe_root(): number;
ubrn_uniffi_loro_ffi_checksum_method_lorodoc_travel_change_ancestors(): number;
ubrn_uniffi_loro_ffi_checksum_method_lorodoc_try_export_json_updates(): number;
ubrn_uniffi_loro_ffi_checksum_method_lorodoc_try_export_json_updates_without_peer_compression(): number;
ubrn_uniffi_loro_ffi_checksum_method_lorodoc_try_get_counter(): number;
ubrn_uniffi_loro_ffi_checksum_method_lorodoc_try_get_list(): number;
ubrn_uniffi_loro_ffi_checksum_method_lorodoc_try_get_map(): number;
Expand Down
Loading
Loading