castrum 0.9.2 → 0.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/Cargo.lock +2259 -0
  2. package/Cargo.toml +138 -0
  3. package/README.md +6 -0
  4. package/build.rs +5 -0
  5. package/castrum.linux-x64-gnu.node +0 -0
  6. package/dist/index.d.ts +1348 -1295
  7. package/dist/index.js +4307 -3776
  8. package/docs/API.md +1 -1
  9. package/docs/ARCHITECTURE.md +3 -2
  10. package/docs/CASE_STUDY.md +2 -2
  11. package/docs/ENVIRONMENT.md +16 -0
  12. package/docs/FFI_BUN_GUIDE.md +89 -6
  13. package/docs/REPO_MAP.md +2 -2
  14. package/index.ts +19 -25
  15. package/package.json +9 -1
  16. package/rust/crypto/aead.rs +378 -0
  17. package/rust/crypto/argon2.rs +265 -0
  18. package/rust/crypto/base64.rs +420 -0
  19. package/rust/crypto/bcrypt.rs +89 -0
  20. package/rust/crypto/cookie_sign.rs +169 -0
  21. package/rust/crypto/csrf.rs +106 -0
  22. package/rust/crypto/ed25519.rs +215 -0
  23. package/rust/crypto/hashing.rs +140 -0
  24. package/rust/crypto/hmac_sha256.rs +88 -0
  25. package/rust/crypto/jwt/api.rs +286 -0
  26. package/rust/crypto/jwt/mod.rs +22 -0
  27. package/rust/crypto/jwt/tests.rs +312 -0
  28. package/rust/crypto/jwt/token.rs +360 -0
  29. package/rust/crypto/mod.rs +27 -0
  30. package/rust/crypto/pbkdf2.rs +96 -0
  31. package/rust/crypto/random_token.rs +85 -0
  32. package/rust/crypto/session.rs +222 -0
  33. package/rust/ffi/crypto.rs +708 -0
  34. package/rust/ffi/hashing.rs +285 -0
  35. package/rust/ffi/http.rs +752 -0
  36. package/rust/ffi/ingress.rs +303 -0
  37. package/rust/ffi/json.rs +517 -0
  38. package/rust/ffi/jwt.rs +419 -0
  39. package/rust/ffi/metrics.rs +373 -0
  40. package/rust/ffi/mod.rs +68 -0
  41. package/rust/ffi/payload.rs +275 -0
  42. package/rust/ffi/probe.rs +60 -0
  43. package/rust/ffi/rate_limit.rs +77 -0
  44. package/rust/ffi/route.rs +85 -0
  45. package/rust/ffi/tests.rs +2333 -0
  46. package/rust/ffi/util.rs +152 -0
  47. package/rust/ffi/validators.rs +123 -0
  48. package/rust/http/accept.rs +606 -0
  49. package/rust/http/cookie_parser.rs +140 -0
  50. package/rust/http/etag.rs +289 -0
  51. package/rust/http/form.rs +132 -0
  52. package/rust/http/headers.rs +267 -0
  53. package/rust/http/http_date.rs +286 -0
  54. package/rust/http/http_parser.rs +252 -0
  55. package/rust/http/media_type.rs +355 -0
  56. package/rust/http/method.rs +200 -0
  57. package/rust/http/mime_lookup.rs +130 -0
  58. package/rust/http/mod.rs +32 -0
  59. package/rust/http/multipart.rs +685 -0
  60. package/rust/http/query_parser.rs +180 -0
  61. package/rust/http/url_codec.rs +296 -0
  62. package/rust/http/url_join.rs +324 -0
  63. package/rust/ingress/api.rs +355 -0
  64. package/rust/ingress/cors.rs +403 -0
  65. package/rust/ingress/ingress_constants.rs +209 -0
  66. package/rust/ingress/ip_trust.rs +312 -0
  67. package/rust/ingress/mod.rs +48 -0
  68. package/rust/ingress/native_route.rs +779 -0
  69. package/rust/ingress/options.rs +176 -0
  70. package/rust/ingress/output.rs +406 -0
  71. package/rust/ingress/packed.rs +191 -0
  72. package/rust/ingress/pipeline.rs +534 -0
  73. package/rust/ingress/proxy.rs +138 -0
  74. package/rust/ingress/rate_limit.rs +538 -0
  75. package/rust/ingress/terminal.rs +114 -0
  76. package/rust/ingress/tests.rs +566 -0
  77. package/rust/ingress/time.rs +70 -0
  78. package/rust/json/fast_schema/capture.rs +336 -0
  79. package/rust/json/fast_schema/compile.rs +556 -0
  80. package/rust/json/fast_schema/cursor.rs +368 -0
  81. package/rust/json/fast_schema/email.rs +282 -0
  82. package/rust/json/fast_schema/errors.rs +247 -0
  83. package/rust/json/fast_schema/mod.rs +57 -0
  84. package/rust/json/fast_schema/tests.rs +1143 -0
  85. package/rust/json/fast_schema/types.rs +140 -0
  86. package/rust/json/fast_schema/validate.rs +931 -0
  87. package/rust/json/json_ops.rs +121 -0
  88. package/rust/json/json_schema.rs +837 -0
  89. package/rust/json/json_ser.rs +881 -0
  90. package/rust/json/mod.rs +19 -0
  91. package/rust/json/napi_marshal.rs +318 -0
  92. package/rust/json/patch/api.rs +60 -0
  93. package/rust/json/patch/engine.rs +153 -0
  94. package/rust/json/patch/mod.rs +47 -0
  95. package/rust/json/patch/ops.rs +270 -0
  96. package/rust/json/patch/pointer.rs +49 -0
  97. package/rust/json/patch/tests.rs +499 -0
  98. package/rust/lib.rs +72 -0
  99. package/rust/metrics/api.rs +148 -0
  100. package/rust/metrics/mod.rs +21 -0
  101. package/rust/metrics/registry.rs +961 -0
  102. package/rust/panic_safety.rs +40 -0
  103. package/rust/payload/compress.rs +512 -0
  104. package/rust/payload/mod.rs +13 -0
  105. package/rust/payload/sse.rs +214 -0
  106. package/rust/payload/template.rs +253 -0
  107. package/rust/payload/websocket.rs +69 -0
  108. package/rust/payload/ws_frames.rs +354 -0
  109. package/rust/proptest_suite.rs +139 -0
  110. package/rust/selection.rs +95 -0
  111. package/rust/src/bin/native-bench.rs +495 -0
  112. package/rust/test_support.rs +71 -0
  113. package/rust/util/batch/api.rs +266 -0
  114. package/rust/util/batch/core.rs +473 -0
  115. package/rust/util/batch/mod.rs +23 -0
  116. package/rust/util/batch/tests.rs +445 -0
  117. package/rust/util/batch_core.rs +184 -0
  118. package/rust/util/bytes.rs +407 -0
  119. package/rust/util/mod.rs +34 -0
  120. package/rust/util/packed.rs +473 -0
  121. package/rust/util/text.rs +130 -0
  122. package/rust/util/threadpool.rs +128 -0
  123. package/rust/util/validation.rs +419 -0
  124. package/rust-toolchain.toml +17 -0
  125. package/scripts/postinstall.mjs +199 -0
  126. package/src/ingress/constants.ts +1 -1
  127. package/src/ingress/context.ts +2 -2
  128. package/src/ingress/decode/baked-result.ts +13 -13
  129. package/src/ingress/decode/fast-result.ts +17 -17
  130. package/src/ingress/errors.ts +7 -7
  131. package/src/ingress/headers/baked-templates.ts +1 -1
  132. package/src/ingress/headers/fast-templates.ts +3 -3
  133. package/src/ingress/index.ts +1 -1
  134. package/src/ingress/native-route.ts +9 -5
  135. package/src/ingress/options.ts +1 -1
  136. package/src/ingress/packing/gather-raw-headers.ts +1 -1
  137. package/src/ingress/packing/route-wire.ts +1 -5
  138. package/src/ingress/response/error-bodies.ts +5 -5
  139. package/src/ingress/response/terminal.ts +1 -1
  140. package/src/ingress/routes/echo.ts +4 -4
  141. package/src/ingress/routes/fallback.ts +2 -2
  142. package/src/ingress/routes/head.ts +2 -2
  143. package/src/ingress/routes/native.ts +2 -1
  144. package/src/ingress/routes/options.ts +1 -1
  145. package/src/ingress/routes/read.ts +2 -2
  146. package/src/ingress/server.ts +10 -6
  147. package/src/ingress/status.ts +7 -7
  148. package/src/integration/batch.ts +1 -1
  149. package/src/integration/index.ts +9 -9
  150. package/src/integration/pipeline.ts +6 -6
  151. package/src/integration/websocket.ts +2 -2
  152. package/src/loader/index.ts +1 -5
  153. package/src/loader/ops.ts +1 -1
  154. package/src/native/ffi/build/codecs.ts +104 -8
  155. package/src/native/ffi/build/compress.ts +14 -10
  156. package/src/native/ffi/build/instances.ts +40 -3
  157. package/src/native/ffi/build/metrics.ts +224 -0
  158. package/src/native/ffi/build/parse.ts +59 -23
  159. package/src/native/ffi/build/util.ts +14 -1
  160. package/src/native/ffi/build.ts +2 -0
  161. package/src/native/ffi/selftest.ts +10 -3
  162. package/src/native/ffi/types.ts +111 -9
  163. package/src/native/ffi.ts +87 -1
  164. package/src/native/index.ts +1 -1
  165. package/src/native/loader.ts +2 -2
  166. package/src/native/types/instances.ts +34 -0
  167. package/src/native/types.ts +11 -0
  168. package/src/runtime/codec.ts +53 -9
  169. package/src/runtime/types.ts +7 -0
  170. package/src/rust-ffi/batch/build.ts +16 -9
  171. package/src/rust-ffi/index.ts +7 -6
  172. package/src/rust-ffi/options.ts +1 -3
  173. package/src/rust-ffi/proven.ts +3 -3
  174. package/src/rust-ffi/scalar/crypto.ts +1 -1
  175. package/src/rust-ffi/scalar/factories.ts +73 -0
  176. package/src/rust-ffi/scalar/hashing.ts +1 -1
  177. package/src/rust-ffi/scalar/http.ts +17 -11
  178. package/src/rust-ffi/scalar/index.ts +2 -0
  179. package/src/rust-ffi/scalar/interface.ts +20 -0
  180. package/src/rust-ffi/scalar/payload.ts +11 -3
  181. package/src/rust-ffi/scalar/validation.ts +121 -0
  182. package/src/selection.ts +1 -1
  183. package/src/shared/bytes.ts +5 -4
  184. package/src/shared/codec.ts +18 -3
@@ -0,0 +1,121 @@
1
+ // rust/json/json_ops.rs — zero-DOM JSON validation/sum + DOM parse.
2
+ //
3
+ // `json_valid_bytes` / `json_sum_ids_bytes` operate on raw bytes with no
4
+ // per-key heap `String` DOM; `json_parse` materializes a `serde_json::Value`
5
+ // when a caller needs the full DOM. Heavily inlined for the hot paths.
6
+
7
+ use napi::bindgen_prelude::*;
8
+ use napi_derive::napi;
9
+ use serde::de::{Deserializer, IgnoredAny, SeqAccess, Visitor};
10
+ use serde::Deserialize;
11
+ use std::fmt;
12
+
13
+ #[derive(Deserialize)]
14
+ struct IdRow {
15
+ #[serde(default)]
16
+ id: Option<i64>,
17
+ }
18
+
19
+ struct IdSumVisitor;
20
+
21
+ impl<'de> Visitor<'de> for IdSumVisitor {
22
+ type Value = i64;
23
+
24
+ #[inline]
25
+ fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
26
+ f.write_str("an array of objects with numeric ids")
27
+ }
28
+
29
+ #[inline]
30
+ fn visit_seq<A: SeqAccess<'de>>(
31
+ self,
32
+ mut seq: A,
33
+ ) -> std::result::Result<Self::Value, A::Error> {
34
+ let mut sum = 0i64;
35
+ while let Some(row) = seq.next_element::<Option<IdRow>>()? {
36
+ if let Some(IdRow { id: Some(id) }) = row {
37
+ sum = sum.saturating_add(id);
38
+ }
39
+ }
40
+ Ok(sum)
41
+ }
42
+ }
43
+
44
+ struct IdSum(i64);
45
+
46
+ impl<'de> Deserialize<'de> for IdSum {
47
+ #[inline]
48
+ fn deserialize<D: Deserializer<'de>>(d: D) -> std::result::Result<Self, D::Error> {
49
+ d.deserialize_seq(IdSumVisitor).map(IdSum)
50
+ }
51
+ }
52
+
53
+ #[inline(always)]
54
+ pub fn json_valid_bytes(input: &[u8]) -> bool {
55
+ // sonic-rs uses SIMD validation internally — already optimal.
56
+ sonic_rs::from_slice::<IgnoredAny>(input).is_ok()
57
+ }
58
+
59
+ #[inline]
60
+ pub fn json_sum_ids_bytes(input: &[u8]) -> Result<i64> {
61
+ sonic_rs::from_slice::<IdSum>(input)
62
+ .map(|s| s.0)
63
+ .map_err(|e| Error::from_reason(e.to_string()))
64
+ }
65
+
66
+ #[napi]
67
+ pub fn json_valid(input: Uint8Array) -> bool {
68
+ json_valid_bytes(input.as_ref())
69
+ }
70
+
71
+ /// Parse JSON into a JS value (sonic-rs → compact `sonic_rs::Value` → hand
72
+ /// written napi marshal). This replaces the old `serde_json::Value` DOM +
73
+ /// generic napi `serde-json` marshal — the sonic Value build is cheaper (no
74
+ /// per-key heap `String`) and the walker avoids serde trait dispatch. Number
75
+ /// marshaling stays byte-parity with the old path (PosInt → BigInt, NegInt/
76
+ /// Float → Number).
77
+ ///
78
+ /// This is the "parse to a usable JS object" path — directly comparable to
79
+ /// `JSON.parse`. Throws on invalid JSON. Note: napi marshaling of the DOM has
80
+ /// real cost, so this is intentionally NOT a zero-copy / validation-only path.
81
+ #[napi]
82
+ pub fn json_parse(env: Env, input: Uint8Array) -> Result<Unknown<'static>> {
83
+ let value: sonic_rs::Value = sonic_rs::from_slice(input.as_ref())
84
+ .map_err(|e| Error::from_reason(format!("JSON parse error: {e}")))?;
85
+ crate::json::napi_marshal::sonic_value_to_js(&env, &value)
86
+ }
87
+
88
+ #[napi]
89
+ pub fn json_sum_ids(input: Uint8Array) -> Result<i64> {
90
+ json_sum_ids_bytes(input.as_ref())
91
+ }
92
+
93
+ #[cfg(test)]
94
+ mod tests {
95
+ use super::*;
96
+
97
+ #[test]
98
+ fn json_parse_roundtrip() {
99
+ let v =
100
+ sonic_rs::from_slice::<serde_json::Value>(br#"{"a":1,"b":[true,null,"x"]}"#).unwrap();
101
+ assert_eq!(v["a"], 1);
102
+ assert_eq!(v["b"][0], true);
103
+ assert_eq!(v["b"][2], "x");
104
+ }
105
+
106
+ #[test]
107
+ fn json_parse_rejects_invalid() {
108
+ assert!(sonic_rs::from_slice::<serde_json::Value>(b"{not json").is_err());
109
+ assert!(sonic_rs::from_slice::<serde_json::Value>(b"").is_err());
110
+ }
111
+
112
+ #[test]
113
+ fn json_valid_matches_parse() {
114
+ let good = br#"{"id":1,"name":"x"}"#;
115
+ assert!(json_valid_bytes(good));
116
+ assert!(sonic_rs::from_slice::<serde_json::Value>(good).is_ok());
117
+ let bad = b"nope";
118
+ assert!(!json_valid_bytes(bad));
119
+ assert!(sonic_rs::from_slice::<serde_json::Value>(bad).is_err());
120
+ }
121
+ }