Skip to content
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
9b8dfea
let's see what claude can do
Oct 31, 2025
91c2e80
more robust
Nov 3, 2025
88817c6
clippy
Nov 3, 2025
9e54c19
remove generated mobile code
Nov 3, 2025
5669d37
use walletkit structure
Nov 3, 2025
3377b14
more like idkit-rs
Nov 3, 2025
72e04ba
doc updates
Nov 3, 2025
cc9fabe
Merge origin/main into full-implementation (accepting main as source …
Nov 4, 2025
6971569
rebase
Nov 4, 2025
be6b262
simpler
Nov 4, 2025
b933520
doc updates
Nov 4, 2025
0edef22
js wasm progress
Nov 6, 2025
9dbc79f
js impl
Nov 6, 2025
8501485
Merge remote-tracking branch 'origin/main' into language-bindings-swi…
Nov 6, 2025
806adcc
simpler
Nov 6, 2025
dbc30e4
remove deprecated cred type
Nov 6, 2025
fa0c7bc
more drop in
Nov 6, 2025
8f434a5
updates to match api
Nov 6, 2025
986e2e8
ci
Nov 6, 2025
e652b19
Potential fix for code scanning alert no. 1: Workflow does not contai…
thereisnogabe Nov 6, 2025
5d96902
Potential fix for code scanning alert no. 2: Workflow does not contai…
thereisnogabe Nov 6, 2025
4012ede
remove old tests
Nov 6, 2025
8906a98
formatting
Nov 6, 2025
b77b0c5
smoke tests
Nov 6, 2025
ed9803e
update
Nov 6, 2025
7e87e9e
update ci
Nov 6, 2025
17edff3
add swift
Nov 6, 2025
6198e8b
remove js
Nov 6, 2025
5cd3cc1
update ci
Nov 6, 2025
96a3c2d
fix ci; pr comments
Nov 6, 2025
284a7f4
pr feedback wip
Nov 6, 2025
79dede9
update tests'
Nov 6, 2025
995ee6f
match existing api
Nov 6, 2025
8fd01cf
Add Swift/macOS support and local development tooling
Nov 6, 2025
3586dfe
Merge branch 'main' into gabe-id-1146-add-rust-core-swift-bindings-ex…
thereisnogabe Nov 6, 2025
6e94fb2
clippy
Nov 6, 2025
09817c1
fix ci
Nov 6, 2025
184ec16
ci
Nov 6, 2025
cb14a09
use bindgen properly
Nov 6, 2025
4b23865
remove dupe
Nov 6, 2025
486547f
fix swift build
Nov 6, 2025
fe7c655
use poll for status
Nov 6, 2025
f93d647
fix ci
Nov 6, 2025
58baebb
clippy
Nov 6, 2025
07311d5
more lints
Nov 6, 2025
3cf4dd6
Set macOS deployment target to match Package.swift
Nov 7, 2025
1290765
Use xcodebuild test instead of swift test in CI
Nov 7, 2025
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
121 changes: 121 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
name: CI
permissions:
contents: read

on:
push:
branches: ['main']
pull_request:

jobs:
rust-core:
name: Rust Core - Build & Test
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4

- name: Setup Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable

- name: Cache Cargo dependencies
uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-

- name: Check formatting
run: cargo fmt --all -- --check

- name: Lint with Clippy
run: cargo clippy --all-targets --all-features -- -D warnings

- name: Build Rust core
run: cargo build --release --package idkit-core

- name: Run Rust tests
run: cargo test --package idkit-core

swift-bindings:
name: Swift Bindings - Build & Test
runs-on: ${{ matrix.os }}
needs: rust-core
strategy:
fail-fast: false
matrix:
include:
- os: macos-15
xcode: "16.0"
- os: macos-15
xcode: "16.1"
env:
DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer
permissions:
contents: read
steps:
- uses: actions/checkout@v4

- name: Setup Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable

- name: Cache Cargo dependencies
uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-

- name: Install uniffi-bindgen
run: cargo install uniffi-bindgen --version 0.30.0

- name: Restore Swift .build cache
id: restore-swift-build
uses: actions/cache/restore@v4
with:
path: swift/.build
restore-keys: "swiftpm-build-${{ runner.os }}-${{ matrix.xcode }}-"
key: "swiftpm-build-${{ runner.os }}-${{ matrix.xcode }}-${{ hashFiles('**/Package.swift', '**/Package.resolved') }}"

- name: Build Rust library
run: cargo build --release --package idkit-uniffi

- name: Generate Swift bindings
run: |
mkdir -p swift/Sources/IDKit/Generated
uniffi-bindgen generate \
--library target/release/libidkit.dylib \
--language swift \
--out-dir swift/Sources/IDKit/Generated

- name: Build Swift package
working-directory: swift
run: swift build

- name: Run Swift tests
working-directory: swift
run: swift test

- name: Cache Swift .build
if: steps.restore-swift-build.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: swift/.build
key: "swiftpm-build-${{ runner.os }}-${{ matrix.xcode }}-${{ hashFiles('**/Package.swift', '**/Package.resolved') }}"
25 changes: 25 additions & 0 deletions .github/workflows/lint-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Validate PR conventions
permissions:
contents: read

on:
pull_request:
types:
- opened
- edited
- synchronize

jobs:
lint-pr:
name: Ensure PR follows conventional commits
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
steps:
- uses: amannn/action-semantic-pull-request@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
validateSingleCommit: true
validateSingleCommitMatchesPrTitle: true
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
*.pdb

# Build outputs (following walletkit model)
# Swift build outputs are not committed to this repo
/swift/Sources/IDKit/
# Swift generated bindings are not committed to this repo (regenerate with scripts/build-swift.sh)
/swift/Sources/IDKit/Generated/
/swift/IDKitFFI.xcframework/
/ios_build/

Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ serde_json = "1.0"

# Cryptography
aes-gcm = "0.10"
getrandom = "0.2"
getrandom = { version = "0.2", features = ["js"] }
tiny-keccak = { version = "2.0", features = ["keccak"] }

# Encoding
Expand Down
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ IDKit is the toolkit for identity online. With IDKit you can easily interact wit

## Packages

### Rust Core
- **`idkit-core`**: Core Rust types (Credential, Request, Proof)
- **`idkit-uniffi`**: UniFFI bindings scaffolding for future Swift/Kotlin support
- **`idkit-wasm`**: WebAssembly bindings scaffolding for future browser support
### Core
- **`rust/core`**: Core Rust library with shared types, credential handling, session management, and cryptography

### Language Bindings
- **`js/packages/core`**: ✅ JavaScript/TypeScript with WASM for browser & Node.js ([docs](./js/packages/core/README.md))
- **`kotlin/`**: Kotlin bindings via UniFFI for Android/JVM
- **`swift/`**: Swift bindings via UniFFI for iOS/macOS

## Documentation

Expand Down
23 changes: 8 additions & 15 deletions rust/core/src/bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{
crypto::{base64_decode, base64_encode, decrypt, encrypt},
error::{AppError, Error, Result},
types::{AppId, BridgeUrl, Proof, Request, Signal, VerificationLevel},
Constraints, ConstraintNode,
ConstraintNode, Constraints,
};
use serde::{Deserialize, Serialize};
use std::time::Duration;
Expand Down Expand Up @@ -210,7 +210,11 @@ impl Session {
return Err(Error::BridgeError(format!(
"Bridge request failed with status {}: {}",
status,
if body.is_empty() { "no error details" } else { &body }
if body.is_empty() {
"no error details"
} else {
&body
}
)));
}

Expand Down Expand Up @@ -255,15 +259,7 @@ impl Session {
.collect(),
));

Self::create_with_options(
app_id,
action,
requests,
None,
Some(constraints),
None,
)
.await
Self::create_with_options(app_id, action, requests, None, Some(constraints), None).await
}

/// Returns the connect URL for World App
Expand All @@ -273,10 +269,7 @@ impl Session {
let bridge_param = if self.bridge_url == BridgeUrl::default() {
String::new()
} else {
format!(
"&b={}",
urlencoding::encode(self.bridge_url.as_str())
)
format!("&b={}", urlencoding::encode(self.bridge_url.as_str()))
};

format!(
Expand Down
10 changes: 8 additions & 2 deletions rust/core/src/constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,10 @@ mod tests {

assert!(node.evaluate(&available));
// Should return Face because it's first in priority order
assert_eq!(node.first_satisfying(&available), Some(CredentialType::Face));
assert_eq!(
node.first_satisfying(&available),
Some(CredentialType::Face)
);
}

#[test]
Expand Down Expand Up @@ -324,7 +327,10 @@ mod tests {

// Only face available
assert!(node.evaluate(&available));
assert_eq!(node.first_satisfying(&available), Some(CredentialType::Face));
assert_eq!(
node.first_satisfying(&available),
Some(CredentialType::Face)
);

// Both available - orb has priority
available.insert(CredentialType::Orb);
Expand Down
6 changes: 4 additions & 2 deletions rust/core/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,10 +371,12 @@ mod tests {

#[test]
fn test_request_validation() {
let valid = Request::new(CredentialType::Orb, Some(Signal::from_string("signal"))).with_face_auth(true);
let valid = Request::new(CredentialType::Orb, Some(Signal::from_string("signal")))
.with_face_auth(true);
assert!(valid.validate().is_ok());

let invalid = Request::new(CredentialType::Device, Some(Signal::from_string("signal"))).with_face_auth(true);
let invalid = Request::new(CredentialType::Device, Some(Signal::from_string("signal")))
.with_face_auth(true);
assert!(invalid.validate().is_err());

// Test without signal
Expand Down
3 changes: 2 additions & 1 deletion rust/uniffi-bindings/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ crate-type = ["staticlib", "cdylib"]
name = "idkit"

[dependencies]
idkit-core = { path = "../core", default-features = false, features = ["uniffi-bindings", "native-crypto"] }
idkit-core = { path = "../core", default-features = false, features = ["uniffi-bindings", "native-crypto", "bridge"] }
uniffi = { workspace = true }
thiserror = { workspace = true }
serde_json = { workspace = true }
hex = { workspace = true }
tokio = { workspace = true, features = ["rt", "rt-multi-thread"] }
Loading
Loading