feat(ios): nbstore swift native binding (#9211)

This commit is contained in:
Brooooooklyn
2024-12-27 06:34:30 +00:00
parent 8de0679d70
commit 752e697c6a
40 changed files with 4544 additions and 234 deletions

View File

@@ -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 */;

View File

@@ -20,6 +20,7 @@ class AFFiNEViewController: CAPBridgeViewController {
HashcashPlugin(),
NavigationGesturePlugin(),
IntelligentsPlugin(representController: self),
NbStorePlugin(),
]
plugins.forEach { bridge?.registerPluginInstance($0) }
}

View File

@@ -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)
}
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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",

View 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();
}
}

View 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);
});
}
}

View 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>;
}

View 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)
);
}
}

View 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();
},
};

View File

@@ -0,0 +1,5 @@
export * from './definitions';
export { nbstoreHandlers } from './handlers';
export { NbStoreDocStorage } from './plugin';
export * from './storage';
export { universalId } from '@affine/nbstore';

View 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,
});
}
}

View 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;
}

View 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();
}
}

View File

@@ -8,5 +8,9 @@
"rootDir": "./src"
},
"include": ["./src"],
"references": [{ "path": "../../core" }]
"references": [
{ "path": "../../core" },
{ "path": "../../native" },
{ "path": "../../../common/nbstore" }
]
}