diff --git a/Cargo.lock b/Cargo.lock index 7d1ca1f..64721ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,17 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "aes" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8eb277bec05f56a0e0591f155a484cbd0f4f07ff2905051a48c72f004f7ed58" +dependencies = [ + "cipher", + "cpubits", + "cpufeatures 0.3.0", +] + [[package]] name = "ahash" version = "0.7.8" @@ -28,12 +39,56 @@ dependencies = [ "memchr", ] +[[package]] +name = "aliasable" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e76a019e91224d279006ff972f1e984179a6e9feb050adba6ce8274aef23195" +dependencies = [ + "alloc-no-stdlib", +] + [[package]] name = "allocator-api2" version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" +[[package]] +name = "allsorts-azul" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab097a7be305dd66b2b6917f5efb6b723129ce4b2cd11aa1a0afcc293c7dc08e" +dependencies = [ + "bitflags", + "brotli-decompressor", + "encoding_rs", + "enumflags2", + "flate2", + "glyph-names", + "log", + "ouroboros", + "pathfinder_geometry", + "rustc-hash", + "tinyvec", + "ucd-trie", + "unicode-canonical-combining-class", + "unicode-general-category", + "unicode-joining-type", +] + [[package]] name = "android_system_properties" version = "0.1.5" @@ -618,6 +673,60 @@ dependencies = [ "tracing", ] +[[package]] +name = "azul-core" +version = "0.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab0b7a3437b72d2e458b8362eb69fd4f9f136465ab750590c398ccf97f976a9e" +dependencies = [ + "azul-css", + "gl-context-loader", + "libm", + "rust-fontconfig", +] + +[[package]] +name = "azul-css" +version = "0.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca878356a1620147ee57559bdd3d7f8fd0d02925211e6f2553c6d24d39eb7d4" +dependencies = [ + "azul-simplecss", + "libm", +] + +[[package]] +name = "azul-layout" +version = "0.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbae4e82c24f18174095b719475bec3a39f326a0176d477699e31f07e9bec98d" +dependencies = [ + "allsorts-azul", + "azul-core", + "azul-css", + "base64", + "hyphenation", + "lru", + "roxmltree", + "rust-fontconfig", + "serde", + "smallvec", + "taffy", + "thiserror", + "tinyvec", + "unicode-bidi", + "unicode-normalization", + "unicode-segmentation", + "xmlparser", + "xmlwriter", +] + +[[package]] +name = "azul-simplecss" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8259ebd5ee48a37fd8931116405456fd67efbb5435b4789e45bdbccf5d7dea7e" + [[package]] name = "backon" version = "1.6.0" @@ -655,6 +764,15 @@ version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "2.13.1" @@ -703,6 +821,15 @@ dependencies = [ "hybrid-array", ] +[[package]] +name = "block-padding" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "710f1dd022ef4e93f8a438b4ba958de7f64308434fa6a87104481645cc30068b" +dependencies = [ + "hybrid-array", +] + [[package]] name = "borsh" version = "1.8.0" @@ -728,14 +855,13 @@ dependencies = [ ] [[package]] -name = "bstr" -version = "1.13.0" +name = "brotli-decompressor" +version = "5.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f7dc094d718f2e1c1559ad110e27eeaae14a5465d3d56dd6dbd793079fbd530" +checksum = "3a32acac15fe1967bc3986b2a6347dffc965602354ea6f450ad07e8bfd253583" dependencies = [ - "memchr", - "regex-automata", - "serde_core", + "alloc-no-stdlib", + "alloc-stdlib", ] [[package]] @@ -823,6 +949,15 @@ dependencies = [ "uuid", ] +[[package]] +name = "cbc" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce2dc9ee5f88d11e0beb842c88b33c8a5cf0d1329c4b19494af42b07dbfe8896" +dependencies = [ + "cipher", +] + [[package]] name = "cc" version = "1.3.0" @@ -872,6 +1007,16 @@ dependencies = [ "windows-link", ] +[[package]] +name = "cipher" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c" +dependencies = [ + "crypto-common 0.2.2", + "inout", +] + [[package]] name = "cmake" version = "0.1.58" @@ -964,6 +1109,7 @@ dependencies = [ "storage", "tracing", "uuid", + "wallet", ] [[package]] @@ -992,6 +1138,12 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "cpubits" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b85f9c39137c3a891689859392b1bd49812121d0d61c9caf00d46ed5ce06ae" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -1274,6 +1426,15 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" +[[package]] +name = "ecb" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbfbf3db731928d6912bc3beda911d55b834cee3df6131ba79b337a1298a3fa9" +dependencies = [ + "cipher", +] + [[package]] name = "ecdsa" version = "0.16.9" @@ -1401,6 +1562,26 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enumflags2" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" +dependencies = [ + "enumflags2_derive", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -1561,6 +1742,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +[[package]] +name = "fst" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a" + [[package]] name = "funty" version = "2.0.0" @@ -1719,6 +1906,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gl-context-loader" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca63cb2488b847c12d1ca56034ba0f15613972c0dc0f8a957f525707567b23d" + +[[package]] +name = "glyph-names" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3531d702d6c1a3ba92a5fb55a404c7b8c476c8e7ca249951077afcbe4bc807f" + [[package]] name = "graphic_designers" version = "0.1.0" @@ -1738,6 +1937,12 @@ dependencies = [ "uuid", ] +[[package]] +name = "grid" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b40ca9252762c466af32d0b1002e91e4e1bc5398f77455e55474deb466355ff5" + [[package]] name = "group" version = "0.13.0" @@ -1814,6 +2019,12 @@ dependencies = [ "hashbrown 0.15.5", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "heck" version = "0.5.0" @@ -2018,6 +2229,29 @@ dependencies = [ "windows-registry", ] +[[package]] +name = "hyphenation" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf4dd4c44ae85155502a52c48739c8a48185d1449fff1963cffee63c28a50f0" +dependencies = [ + "bincode", + "fst", + "hyphenation_commons", + "pocket-resources", + "serde", +] + +[[package]] +name = "hyphenation_commons" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5febe7a2ade5c7d98eb8b75f946c046b335324b06a14ea0998271504134c05bf" +dependencies = [ + "fst", + "serde", +] + [[package]] name = "iana-time-zone" version = "0.1.65" @@ -2155,6 +2389,16 @@ dependencies = [ "hashbrown 0.17.1", ] +[[package]] +name = "inout" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" +dependencies = [ + "block-padding", + "hybrid-array", +] + [[package]] name = "invoice" version = "0.1.0" @@ -2362,12 +2606,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - [[package]] name = "linux-raw-sys" version = "0.12.1" @@ -2397,18 +2635,27 @@ checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" [[package]] name = "lopdf" -version = "0.31.0" +version = "0.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07c8e1b6184b1b32ea5f72f572ebdc40e5da1d2921fa469947ff7c480ad1f85a" +checksum = "5e2ec995d822e05cabc3f06d196ee43650af3fe4fe38012cacb35e0c3d113b68" dependencies = [ + "aes", + "bitflags", + "cbc", + "ecb", "encoding_rs", "flate2", + "getrandom 0.4.3", + "indexmap", "itoa", - "linked-hash-map", "log", - "md5", - "pom", - "time", + "md-5 0.11.0", + "nom", + "rand 0.10.2", + "rangemap", + "sha2 0.11.0", + "stringprep", + "thiserror", "weezl", ] @@ -2481,12 +2728,6 @@ dependencies = [ "digest 0.11.3", ] -[[package]] -name = "md5" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" - [[package]] name = "memchr" version = "2.8.3" @@ -2530,6 +2771,16 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "mmapio" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0204e2cac68f5b2e35b7ec8cb5d906f6e58e78dad8066a30b6ee54da99bb03dd" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "multer" version = "3.1.0" @@ -2692,21 +2943,36 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "ouroboros" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59" +dependencies = [ + "aliasable", + "ouroboros_macro", + "static_assertions", +] + +[[package]] +name = "ouroboros_macro" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn 2.0.119", +] + [[package]] name = "outref" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" -[[package]] -name = "owned_ttf_parser" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "706de7e2214113d63a8238d1910463cfce781129a6f263d13fdb09ff64355ba4" -dependencies = [ - "ttf-parser", -] - [[package]] name = "p256" version = "0.13.2" @@ -2771,6 +3037,25 @@ dependencies = [ "subtle", ] +[[package]] +name = "pathfinder_geometry" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b7e7b4ea703700ce73ebf128e1450eb69c3a8329199ffbfb9b2a0418e5ad3" +dependencies = [ + "log", + "pathfinder_simd", +] + +[[package]] +name = "pathfinder_simd" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4500030c302e4af1d423f36f3b958d1aecb6c04184356ed5a833bf6b60435777" +dependencies = [ + "rustc_version", +] + [[package]] name = "payments" version = "0.1.0" @@ -2885,13 +3170,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] -name = "pom" -version = "3.4.0" +name = "pocket-resources" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c972d8f86e943ad532d0b04e8965a749ad1d18bb981a9c7b3ae72fe7fd7744b" -dependencies = [ - "bstr", -] +checksum = "c135f38778ad324d9e9ee68690bac2c1a51f340fdf96ca13e2ab3914eb2e51d8" [[package]] name = "postgres-protocol" @@ -2957,14 +3239,28 @@ dependencies = [ [[package]] name = "printpdf" -version = "0.7.0" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c30a4cc87c3ca9a98f4970db158a7153f8d1ec8076e005751173c57836380b1d" +checksum = "8830a8a6c6431286333c8a64d109f7f0e7e050270c8b8eba0a4c541626059da5" dependencies = [ - "js-sys", + "allsorts-azul", + "azul-core", + "azul-css", + "azul-layout", + "base64", + "flate2", + "getrandom 0.4.3", "lopdf", - "owned_ttf_parser", + "rust-fontconfig", + "serde", + "serde_derive", + "serde_json", + "smallvec", "time", + "wasm-bindgen", + "wasm-bindgen-futures", + "weezl", + "xmlparser", ] [[package]] @@ -2985,6 +3281,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "version_check", + "yansi", +] + [[package]] name = "ptr_meta" version = "0.1.4" @@ -3144,6 +3453,12 @@ dependencies = [ "rand_core 0.10.1", ] +[[package]] +name = "rangemap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "973443cf09a9c8656b574a866ab68dfa19f0867d0340648c7d2f6a71b8a8ea68" + [[package]] name = "redis" version = "0.27.6" @@ -3333,6 +3648,15 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "roxmltree" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1964b10c76125c36f8afe190065a4bf9a87bf324842c05701330bba9f1cacbb" +dependencies = [ + "memchr", +] + [[package]] name = "rsa" version = "0.9.10" @@ -3353,6 +3677,17 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rust-fontconfig" +version = "4.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87542166cd2a7b38cf2c338384d882656e2fbbdd9813017415f1d57ad35757e9" +dependencies = [ + "allsorts-azul", + "mmapio", + "xmlparser", +] + [[package]] name = "rust_decimal" version = "1.42.1" @@ -3706,6 +4041,15 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" +[[package]] +name = "slotmap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" +dependencies = [ + "version_check", +] + [[package]] name = "smallvec" version = "1.15.2" @@ -3851,7 +4195,7 @@ checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b" dependencies = [ "dotenvy", "either", - "heck", + "heck 0.5.0", "hex", "once_cell", "proc-macro2", @@ -3983,6 +4327,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "storage" version = "0.1.0" @@ -4091,6 +4441,18 @@ dependencies = [ "libc", ] +[[package]] +name = "taffy" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aea22054047c16c3f34d3ac473a2170be1424b1115b2a3adcf28cfb067c88859" +dependencies = [ + "arrayvec", + "grid", + "serde", + "slotmap", +] + [[package]] name = "tap" version = "1.0.1" @@ -4412,12 +4774,6 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "ttf-parser" -version = "0.19.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49d64318d8311fc2668e48b63969f4343e0a85c4a109aa8460d6672e364b8bd1" - [[package]] name = "tutors" version = "0.1.0" @@ -4443,6 +4799,12 @@ version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + [[package]] name = "ugc_content_creators" version = "0.1.0" @@ -4474,12 +4836,30 @@ version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" +[[package]] +name = "unicode-canonical-combining-class" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41c99d5174052d02ce765418e826597a1be18f32c114e35d9e22f92390239561" + +[[package]] +name = "unicode-general-category" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b993bddc193ae5bd0d623b49ec06ac3e9312875fdae725a975c51db1cc1677f" + [[package]] name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-joining-type" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8d00a78170970967fdb83f9d49b92f959ab2bb829186b113e4f4604ad98e180" + [[package]] name = "unicode-normalization" version = "0.1.25" @@ -4495,6 +4875,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + [[package]] name = "untrusted" version = "0.9.0" @@ -4612,6 +4998,19 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" +[[package]] +name = "wallet" +version = "0.1.0" +dependencies = [ + "chrono", + "serde", + "serde_json", + "sqlx", + "thiserror", + "tracing", + "uuid", +] + [[package]] name = "want" version = "0.3.1" @@ -4742,9 +5141,9 @@ dependencies = [ [[package]] name = "weezl" -version = "0.1.12" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" +checksum = "d4ca08e5ef825b65b056d9efbd95c8750683f0a6d0466d02e96dc2e4e360f3d2" [[package]] name = "whoami" @@ -4756,6 +5155,28 @@ dependencies = [ "wasite", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-core" version = "0.62.2" @@ -5004,6 +5425,18 @@ version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" +[[package]] +name = "xmlwriter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + [[package]] name = "yoke" version = "0.8.3" diff --git a/apps/cron/src/tasks/auto_apply.rs b/apps/cron/src/tasks/auto_apply.rs index cd67ce0..45df4bc 100644 --- a/apps/cron/src/tasks/auto_apply.rs +++ b/apps/cron/src/tasks/auto_apply.rs @@ -175,7 +175,9 @@ pub async fn run_auto_apply(pool: &PgPool) -> Result<(), Box = sqlx::query_as( r#" SELECT @@ -194,11 +196,13 @@ pub async fn run_auto_apply(pool: &PgPool) -> Result<(), Box= uas.current_period_start AND NOW() < uas.current_period_end + AND ap.allowed_features ? 'auto_apply_execute' "#, ) .fetch_all(pool) diff --git a/apps/job_seekers/Cargo.toml b/apps/job_seekers/Cargo.toml index 3889baf..dbd7892 100644 --- a/apps/job_seekers/Cargo.toml +++ b/apps/job_seekers/Cargo.toml @@ -21,6 +21,6 @@ email = { path = "../../crates/email" } serde_json = { workspace = true } redis = { workspace = true } cache = { path = "../../crates/cache" } -printpdf = { workspace = true } +printpdf = "0.12.5" anyhow = { workspace = true } diff --git a/apps/job_seekers/src/handlers.rs b/apps/job_seekers/src/handlers.rs index d53b837..724bdad 100644 --- a/apps/job_seekers/src/handlers.rs +++ b/apps/job_seekers/src/handlers.rs @@ -238,73 +238,69 @@ fn build_resume_pdf( skills: &str, ) -> Result, Box> { use printpdf::*; - use std::io::{BufWriter, Cursor}; - let (doc, page1, layer1) = PdfDocument::new( - &format!("{} - Resume", name), - Mm(210.0), - Mm(297.0), - "Resume", - ); - let layer = doc.get_page(page1).get_layer(layer1); + // Push a single text span at a specific (x, y) position in mm. + fn push_text(ops: &mut Vec, text: &str, size: f32, x: f32, y: f32, font: BuiltinFont) { + ops.push(Op::StartTextSection); + ops.push(Op::SetTextCursor { pos: Point::new(Mm(x), Mm(y)) }); + ops.push(Op::SetFont { font: PdfFontHandle::Builtin(font), size: Pt(size) }); + ops.push(Op::ShowText { items: vec![TextItem::Text(text.to_string())] }); + ops.push(Op::EndTextSection); + } - let regular = doc.add_builtin_font(BuiltinFont::Helvetica)?; - let bold = doc.add_builtin_font(BuiltinFont::HelveticaBold)?; + let mut ops: Vec = Vec::new(); + let left = 20.0_f32; + let mut y = 276.0_f32; - let left: Mm = Mm(20.0); - let mut y: f32 = 276.0; - - // Name - layer.use_text(name, 20.0, left, Mm(y), &bold); + // Name (large, bold) + push_text(&mut ops, name, 20.0, left, y, BuiltinFont::HelveticaBold); y -= 9.0; // Headline if !headline.is_empty() { - layer.use_text(headline, 11.0, left, Mm(y), ®ular); + push_text(&mut ops, headline, 11.0, left, y, BuiltinFont::Helvetica); y -= 5.0; } - // Separator (text-based) - layer.use_text("___________________________________________________", 9.0, left, Mm(y), ®ular); + // Separator + push_text(&mut ops, "___________________________________________________", 9.0, left, y, BuiltinFont::Helvetica); y -= 8.0; - // Helper: render one section — header then wrapped body lines - let mut render_section = |label: &str, content: &str| { - if content.trim().is_empty() { return; } - if y < 20.0 { return; } - // Section header in bold - layer.use_text(label, 9.5, left, Mm(y), &bold); + // Sections: bold header then wrapped body lines + for (label, content) in [ + ("PROFESSIONAL SUMMARY", summary), + ("SKILLS", skills), + ("EDUCATION", education), + ("WORK EXPERIENCE", work_experience), + ] { + if content.trim().is_empty() || y < 20.0 { continue; } + push_text(&mut ops, label, 9.5, left, y, BuiltinFont::HelveticaBold); y -= 5.5; - // Body text, word-wrapped for line in wrap_text(content, 88) { if y < 20.0 { break; } if line.is_empty() { y -= 2.5; } else { - layer.use_text(&line, 9.5, left, Mm(y), ®ular); + push_text(&mut ops, &line, 9.5, left, y, BuiltinFont::Helvetica); y -= 5.0; } } y -= 4.0; - }; - - render_section("PROFESSIONAL SUMMARY", summary); - render_section("SKILLS", skills); - render_section("EDUCATION", education); - render_section("WORK EXPERIENCE", work_experience); + } // Privacy footer - layer.use_text( + push_text( + &mut ops, "* Contact details are hidden. Use Nxtgauge to unlock and connect with this candidate.", - 7.5, - left, - Mm(12.0), - ®ular, + 7.5, left, 12.0, BuiltinFont::Helvetica, ); - let mut buf = Vec::new(); - doc.save(&mut BufWriter::new(Cursor::new(&mut buf)))?; - Ok(buf) + let page = PdfPage::new(Mm(210.0), Mm(297.0), ops); + let bytes = PdfDocument::new(&format!("{} - Resume", name)) + .with_pages(vec![page]) + .save(&PdfSaveOptions::default(), &mut Vec::new()); + + Ok(bytes) } async fn browse_jobs( diff --git a/apps/users/src/handlers/ai.rs b/apps/users/src/handlers/ai.rs index 3a1d9e5..38822e8 100644 --- a/apps/users/src/handlers/ai.rs +++ b/apps/users/src/handlers/ai.rs @@ -1044,12 +1044,18 @@ async fn ai_generate_job_field( Some(w) => db::models::ai_credits::AiCreditsRepository::get_plan(&state.pool, w.plan_id).await.ok().flatten(), None => None, }; + let daily_limit = plan.as_ref().map(|p| p.daily_action_limit).unwrap_or(0); + // Fix: return remaining daily ACTIONS (not total credit balance) so the + // frontend "AI generations left today" counter stays accurate for paid users. + let remaining_today = wallet.as_ref().zip(plan.as_ref()) + .map(|(w, p)| (p.daily_action_limit as i64 - w.daily_actions_used as i64).max(0) as i32) + .unwrap_or(0); ( StatusCode::OK, Json(GenerateFieldResponse { generated_text: outcome.result.trim().to_string(), - remaining_today: wallet.as_ref().map(|w| w.available_credits()).unwrap_or(0), - daily_limit: plan.map(|p| p.daily_action_limit).unwrap_or(0), + remaining_today, + daily_limit, has_ai_pack: wallet.as_ref().map(|w| w.purchased_credits_total > 0).unwrap_or(false), credits_charged: None, remaining_credits: None, @@ -1179,12 +1185,18 @@ async fn ai_generate_cover_letter( Some(w) => db::models::ai_credits::AiCreditsRepository::get_plan(&state.pool, w.plan_id).await.ok().flatten(), None => None, }; + let daily_limit = plan.as_ref().map(|p| p.daily_action_limit).unwrap_or(0); + // Fix: return remaining daily ACTIONS (not total credit balance) so the + // frontend "AI generations left today" counter stays accurate for paid users. + let remaining_today = wallet.as_ref().zip(plan.as_ref()) + .map(|(w, p)| (p.daily_action_limit as i64 - w.daily_actions_used as i64).max(0) as i32) + .unwrap_or(0); ( StatusCode::OK, Json(GenerateFieldResponse { generated_text: outcome.result.trim().to_string(), - remaining_today: wallet.as_ref().map(|w| w.available_credits()).unwrap_or(0), - daily_limit: plan.map(|p| p.daily_action_limit).unwrap_or(0), + remaining_today, + daily_limit, has_ai_pack: wallet.as_ref().map(|w| w.purchased_credits_total > 0).unwrap_or(false), credits_charged: None, remaining_credits: None, @@ -1310,12 +1322,18 @@ async fn ai_tailor_resume( Some(w) => db::models::ai_credits::AiCreditsRepository::get_plan(&state.pool, w.plan_id).await.ok().flatten(), None => None, }; + let daily_limit = plan.as_ref().map(|p| p.daily_action_limit).unwrap_or(0); + // Fix: return remaining daily ACTIONS (not total credit balance) so the + // frontend "AI generations left today" counter stays accurate for paid users. + let remaining_today = wallet.as_ref().zip(plan.as_ref()) + .map(|(w, p)| (p.daily_action_limit as i64 - w.daily_actions_used as i64).max(0) as i32) + .unwrap_or(0); ( StatusCode::OK, Json(GenerateFieldResponse { generated_text: outcome.result.trim().to_string(), - remaining_today: wallet.as_ref().map(|w| w.available_credits()).unwrap_or(0), - daily_limit: plan.map(|p| p.daily_action_limit).unwrap_or(0), + remaining_today, + daily_limit, has_ai_pack: wallet.as_ref().map(|w| w.purchased_credits_total > 0).unwrap_or(false), credits_charged: None, remaining_credits: None, @@ -1486,7 +1504,7 @@ async fn ai_auto_apply( let result = sqlx::query( r#" - INSERT INTO job_applications (job_id, applicant_user_id, cover_letter, applied_via_ai) + INSERT INTO job_applications (job_id, applicant_user_id, cover_note, applied_via_ai) VALUES ($1, $2, $3, true) ON CONFLICT (job_id, applicant_user_id) DO NOTHING "# @@ -1699,6 +1717,9 @@ async fn ai_usage_status( "purchased_credits_used": sub.purchased_credits_used, "plan_code": plan.code, "plan_name": plan.name, + // Expose the feature list so frontends can gate premium UI + // without making a second round-trip. + "allowed_features": plan.allowed_features, }) } Err(e) => { diff --git a/crates/contracts/Cargo.toml b/crates/contracts/Cargo.toml index 8b0cf29..af654cf 100644 --- a/crates/contracts/Cargo.toml +++ b/crates/contracts/Cargo.toml @@ -17,4 +17,5 @@ jsonwebtoken = { version = "10.3", features = ["rust_crypto"] } db = { path = "../db" } cache = { path = "../cache" } storage = { path = "../storage" } +wallet = { path = "../wallet" } bytes.workspace = true diff --git a/crates/contracts/src/profession_shared.rs b/crates/contracts/src/profession_shared.rs index 2598346..dc2edfb 100644 --- a/crates/contracts/src/profession_shared.rs +++ b/crates/contracts/src/profession_shared.rs @@ -10,6 +10,7 @@ use serde::Deserialize; use uuid::Uuid; use db::models::lead_request::{CreateLeadRequestPayload, LeadRequestRepository}; use db::models::tracecoin_wallet::TracecoinWalletRepository; +use wallet::hold as tracecoin_hold; use db::models::requirement::RequirementRepository; use db::models::professional::{ CreatePortfolioItemPayload, @@ -110,6 +111,8 @@ pub fn shared_routes(profession_key: &'static str) -> Router { .route("/wallet/me/ledger", get(wallet_ledger)) .route("/wallet/me/invoices", get(wallet_invoices)) .route("/wallet/me/invoices/{id}", get(wallet_invoice_detail)) + .route("/wallet/me/holds", get(wallet_holds)) + .route("/wallet/me/holds/{id}/release", post(wallet_release_hold)) } // ── Handlers ────────────────────────────────────────────────────────────────── @@ -801,6 +804,55 @@ async fn wallet_invoice_detail( } } +/// List all holds (any status) for the authenticated professional, newest first. +/// Returns `{ "data": [...], "pagination": { "page": 1, "limit": N } }`. +async fn wallet_holds( + State(state): State, + auth: AuthUser, + Query(q): Query, +) -> impl IntoResponse { + let limit = q.limit.unwrap_or(50).clamp(1, 200) as i64; + let page = q.page.unwrap_or(1).max(1); + + match tracecoin_hold::list_for_user(&state.pool, auth.user_id, limit).await { + Ok(items) => (StatusCode::OK, Json(serde_json::json!({ + "data": items, + "pagination": { "page": page, "limit": limit } + }))).into_response(), + Err(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response(), + } +} + +/// Release an ACTIVE hold owned by the authenticated professional. +/// The tracecoins are returned to the user's available balance. +async fn wallet_release_hold( + State(state): State, + auth: AuthUser, + Path(id): Path, +) -> impl IntoResponse { + // Verify ownership before releasing: fetch the hold and confirm user_id matches. + match tracecoin_hold::list_for_user(&state.pool, auth.user_id, 200).await { + Ok(holds) => { + let owned = holds.iter().any(|h| h.id == id); + if !owned { + return (StatusCode::NOT_FOUND, "Hold not found or not yours").into_response(); + } + } + Err(e) => return (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response(), + } + + match tracecoin_hold::release(&state.pool, id).await { + Ok(()) => (StatusCode::OK, Json(serde_json::json!({ + "message": "Hold released. Tracecoins returned to your available balance." + }))).into_response(), + Err(wallet::hold::HoldError::NotFound) => + (StatusCode::NOT_FOUND, "Hold not found").into_response(), + Err(wallet::hold::HoldError::NotActive(s)) => + (StatusCode::CONFLICT, format!("Hold is not active (status: {s})")).into_response(), + Err(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response(), + } +} + async fn submit_for_verification( State(state): State, auth: AuthUser, diff --git a/deny.toml b/deny.toml new file mode 100644 index 0000000..c0028fe --- /dev/null +++ b/deny.toml @@ -0,0 +1,59 @@ +# cargo-deny configuration for nxtgauge-backend-rust +# https://embarkstudios.github.io/cargo-deny/ +# +# For this private/proprietary workspace we only enforce: +# - advisories (CVEs / RustSec) +# - bans (forbidden crates, duplicate versions) +# License compliance is skipped — our internal crates have no license field. + +[graph] +targets = [] + +# ── Advisories (CVEs / RustSec) ────────────────────────────────────────────── +[advisories] +version = 2 +db-path = "~/.cargo/advisory-db" +db-urls = ["https://github.com/rustsec/advisory-db"] +ignore = [ + # RUSTSEC-2023-0071 - rsa: Marvin Attack timing side-channel — no upstream fix available. + # Impact: potential RSA key recovery via timing. Low risk: we use RSA only for JWT + # verification (public-key ops), not for decryption. Acknowledged. + "RUSTSEC-2023-0071", + # RUSTSEC-2025-0141 - bincode: unmaintained (not a vulnerability, just no active maintainer). + # bincode is used transitively; no replacement available in our dep tree. + "RUSTSEC-2025-0141", +] + +# ── Bans (duplicate deps / forbidden crates) ────────────────────────────────── +[bans] +# Warn on multiple versions of the same crate. +multiple-versions = "warn" +# Crates we never want in the dependency tree. +deny = [ + # Avoid the old `time` crate (use chrono / time 0.3 instead) + { name = "time", version = "=0.1" }, +] + +# ── Licenses (skipped for private workspace) ────────────────────────────────── +# We do not enforce license policy here because: +# - All our own workspace crates are proprietary and unpublished. +# - Third-party license compliance is managed separately. +[licenses] +version = 2 +allow = ["MIT", "Apache-2.0", "Apache-2.0 WITH LLVM-exception", "BSD-2-Clause", "BSD-3-Clause", "ISC", "Unicode-3.0", "Unicode-DFS-2016", "CC0-1.0", "Zlib", "OpenSSL"] +confidence-threshold = 0.6 + +[[licenses.clarify]] +name = "ring" +expression = "MIT AND ISC AND OpenSSL" +license-files = [{ path = "LICENSE", hash = 0xbd0eed23 }] + +[[licenses.exceptions]] +allow = ["LicenseRef-Private"] +crate = "auth" + +# ── Sources ─────────────────────────────────────────────────────────────────── +[sources] +unknown-registry = "deny" +unknown-git = "deny" +allow-registry = ["https://github.com/rust-lang/crates.io-index"]