app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

commit b261738f55f9c7bcc90ec84c308a8d28eea3d568
parent ec575484da02cf9aa3f9c07eacf6e3b2102d64bb
Author: triesap <triesap@radroots.dev>
Date:   Mon, 19 Jan 2026 07:10:35 +0000

app-utils: add id helpers

- add uuidv4 and uuidv7 helpers
- add base64url encoding variants
- add d_tag_create alias helper
- add unit tests for id formats

Diffstat:
MCargo.lock | 2++
MCargo.toml | 1+
Mcrates/utils/Cargo.toml | 2++
Acrates/utils/src/id/mod.rs | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcrates/utils/src/lib.rs | 2++
5 files changed, 62 insertions(+), 0 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -1575,12 +1575,14 @@ dependencies = [ name = "radroots-app-utils" version = "0.1.0" dependencies = [ + "base64", "futures", "getrandom 0.2.17", "gloo-timers", "js-sys", "radroots-types", "serde_json", + "uuid", "web-sys", ] diff --git a/Cargo.toml b/Cargo.toml @@ -70,6 +70,7 @@ url = "2" chrono = "0.4" hex = "0.4" sha2 = "0.10" +uuid = { version = "1.8", features = ["v4", "v7"] } radroots-nostr = { path = "refs/crates/nostr" } radroots-types = { path = "refs/crates/types" } radroots-sql-core = { path = "refs/crates/sql-core" } diff --git a/crates/utils/Cargo.toml b/crates/utils/Cargo.toml @@ -15,6 +15,8 @@ getrandom = { workspace = true } js-sys = { workspace = true } web-sys = { workspace = true } serde_json = { workspace = true } +uuid = { workspace = true } +base64 = { workspace = true } [target.'cfg(target_arch = "wasm32")'.dependencies] gloo-timers = { workspace = true } diff --git a/crates/utils/src/id/mod.rs b/crates/utils/src/id/mod.rs @@ -0,0 +1,55 @@ +#![forbid(unsafe_code)] + +use base64::engine::general_purpose::URL_SAFE_NO_PAD; +use base64::Engine; +use uuid::Uuid; + +pub fn uuidv4() -> String { + Uuid::new_v4().to_string() +} + +pub fn uuidv7() -> String { + Uuid::now_v7().to_string() +} + +pub fn uuidv4_b64url() -> String { + URL_SAFE_NO_PAD.encode(Uuid::new_v4().as_bytes()) +} + +pub fn uuidv7_b64url() -> String { + URL_SAFE_NO_PAD.encode(Uuid::now_v7().as_bytes()) +} + +pub fn d_tag_create() -> String { + uuidv7_b64url() +} + +#[cfg(test)] +mod tests { + use super::{d_tag_create, uuidv4, uuidv4_b64url, uuidv7, uuidv7_b64url}; + + #[test] + fn uuidv4_has_expected_length() { + assert_eq!(uuidv4().len(), 36); + } + + #[test] + fn uuidv7_has_expected_length() { + assert_eq!(uuidv7().len(), 36); + } + + #[test] + fn uuidv4_b64url_has_expected_length() { + assert_eq!(uuidv4_b64url().len(), 22); + } + + #[test] + fn uuidv7_b64url_has_expected_length() { + assert_eq!(uuidv7_b64url().len(), 22); + } + + #[test] + fn d_tag_create_uses_uuidv7_b64url() { + assert_eq!(d_tag_create().len(), 22); + } +} diff --git a/crates/utils/src/lib.rs b/crates/utils/src/lib.rs @@ -4,6 +4,7 @@ pub mod error; pub mod errors; pub mod r#async; pub mod binary; +pub mod id; pub mod numbers; pub mod object; pub mod path; @@ -13,6 +14,7 @@ pub mod types; pub use r#async::exe_iter; pub use binary::{as_array_buffer, RadrootsAppArrayBuffer}; +pub use id::{d_tag_create, uuidv4, uuidv4_b64url, uuidv7, uuidv7_b64url}; pub use errors::{err_msg, handle_err, throw_err, ERR_PREFIX_APP, ERR_PREFIX_UTILS}; pub use numbers::{num_interval_range, num_str, parse_float, parse_int}; pub use object::{obj_en, obj_result, obj_results_str, obj_truthy_fields};