@zap-js/server 0.0.1 → 0.0.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.
package/src/request.rs DELETED
@@ -1,60 +0,0 @@
1
- //! Request types and utilities for ZapServer
2
-
3
- use std::collections::HashMap;
4
- use zap_core::{Request, Method};
5
-
6
- /// Request data that can be owned and moved between threads
7
- #[derive(Debug, Clone)]
8
- pub struct RequestData {
9
- pub method: Method,
10
- pub path: String,
11
- pub path_only: String,
12
- pub version: String,
13
- pub headers: HashMap<String, String>,
14
- pub body: Vec<u8>,
15
- pub params: HashMap<String, String>,
16
- pub query: HashMap<String, String>,
17
- pub cookies: HashMap<String, String>,
18
- }
19
-
20
- impl RequestData {
21
- /// Create RequestData from a borrowed Request
22
- pub fn from_request(req: &Request) -> Self {
23
- Self {
24
- method: req.method(),
25
- path: req.path().to_string(),
26
- path_only: req.path_only().to_string(),
27
- version: req.version().to_string(),
28
- headers: req.headers().iter().map(|(k, v)| (k.to_string(), v.to_string())).collect(),
29
- body: req.body().to_vec(),
30
- params: req.params().iter().map(|(k, v)| (k.to_string(), v.to_string())).collect(),
31
- query: req.query_params().into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect(),
32
- cookies: req.cookies().into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect(),
33
- }
34
- }
35
-
36
- /// Get parameter by name
37
- pub fn param(&self, name: &str) -> Option<&str> {
38
- self.params.get(name).map(|s| s.as_str())
39
- }
40
-
41
- /// Get query parameter by name
42
- pub fn query(&self, name: &str) -> Option<&str> {
43
- self.query.get(name).map(|s| s.as_str())
44
- }
45
-
46
- /// Get header by name
47
- pub fn header(&self, name: &str) -> Option<&str> {
48
- self.headers.get(name).map(|s| s.as_str())
49
- }
50
-
51
- /// Get cookie by name
52
- pub fn cookie(&self, name: &str) -> Option<&str> {
53
- self.cookies.get(name).map(|s| s.as_str())
54
- }
55
-
56
- /// Get body as string
57
- pub fn body_string(&self) -> Result<String, std::string::FromUtf8Error> {
58
- String::from_utf8(self.body.clone())
59
- }
60
- }
package/src/request_id.rs DELETED
@@ -1,97 +0,0 @@
1
- //! Request ID generation and extraction for request correlation
2
- //!
3
- //! Provides unique identifiers for each request that flow through
4
- //! the entire system (Rust server -> IPC -> TypeScript handlers).
5
- //! This enables end-to-end request tracing in logs and metrics.
6
-
7
- use uuid::Uuid;
8
-
9
- /// Standard header name for request ID
10
- pub const REQUEST_ID_HEADER: &str = "x-request-id";
11
-
12
- /// Generate a new UUID v4 request ID
13
- #[inline]
14
- pub fn generate() -> String {
15
- Uuid::new_v4().to_string()
16
- }
17
-
18
- /// Extract request ID from headers or generate a new one
19
- ///
20
- /// Checks for both lowercase and mixed-case header names.
21
- pub fn get_or_generate(headers: &std::collections::HashMap<String, String>) -> String {
22
- // Check lowercase first (normalized headers)
23
- if let Some(id) = headers.get(REQUEST_ID_HEADER) {
24
- if !id.is_empty() {
25
- return id.clone();
26
- }
27
- }
28
-
29
- // Check mixed-case variant
30
- if let Some(id) = headers.get("X-Request-ID") {
31
- if !id.is_empty() {
32
- return id.clone();
33
- }
34
- }
35
-
36
- // Check another common variant
37
- if let Some(id) = headers.get("X-Request-Id") {
38
- if !id.is_empty() {
39
- return id.clone();
40
- }
41
- }
42
-
43
- generate()
44
- }
45
-
46
- /// Validate that a request ID looks reasonable
47
- /// (not empty, not too long, alphanumeric + hyphens)
48
- pub fn is_valid(id: &str) -> bool {
49
- if id.is_empty() || id.len() > 128 {
50
- return false;
51
- }
52
-
53
- id.chars()
54
- .all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '_')
55
- }
56
-
57
- #[cfg(test)]
58
- mod tests {
59
- use super::*;
60
-
61
- #[test]
62
- fn test_generate_unique() {
63
- let id1 = generate();
64
- let id2 = generate();
65
- assert_ne!(id1, id2);
66
- assert!(is_valid(&id1));
67
- assert!(is_valid(&id2));
68
- }
69
-
70
- #[test]
71
- fn test_get_or_generate_extracts() {
72
- let mut headers = std::collections::HashMap::new();
73
- headers.insert("x-request-id".to_string(), "test-123".to_string());
74
-
75
- let id = get_or_generate(&headers);
76
- assert_eq!(id, "test-123");
77
- }
78
-
79
- #[test]
80
- fn test_get_or_generate_creates() {
81
- let headers = std::collections::HashMap::new();
82
- let id = get_or_generate(&headers);
83
- assert!(is_valid(&id));
84
- // Should be UUID format
85
- assert!(id.contains('-'));
86
- }
87
-
88
- #[test]
89
- fn test_is_valid() {
90
- assert!(is_valid("abc-123"));
91
- assert!(is_valid("550e8400-e29b-41d4-a716-446655440000"));
92
- assert!(is_valid("request_123"));
93
- assert!(!is_valid(""));
94
- assert!(!is_valid(&"a".repeat(200)));
95
- assert!(!is_valid("test@123")); // @ not allowed
96
- }
97
- }
package/src/response.rs DELETED
@@ -1,182 +0,0 @@
1
- //! Response types and utilities for ZapServer
2
-
3
- use std::collections::HashMap;
4
- use std::path::PathBuf;
5
-
6
- use bytes::Bytes;
7
- use serde::Serialize;
8
-
9
- use zap_core::{Response, StatusCode, ResponseBody};
10
-
11
- /// Streaming response data
12
- #[derive(Debug)]
13
- pub struct StreamingResponse {
14
- /// HTTP status code
15
- pub status: u16,
16
- /// Response headers
17
- pub headers: HashMap<String, String>,
18
- /// Collected body chunks (base64 decoded)
19
- pub chunks: Vec<Vec<u8>>,
20
- }
21
-
22
- impl StreamingResponse {
23
- /// Create a new streaming response
24
- pub fn new(status: u16, headers: HashMap<String, String>) -> Self {
25
- Self {
26
- status,
27
- headers,
28
- chunks: Vec::new(),
29
- }
30
- }
31
-
32
- /// Add a chunk to the response
33
- pub fn add_chunk(&mut self, data: Vec<u8>) {
34
- self.chunks.push(data);
35
- }
36
-
37
- /// Get the complete body as bytes
38
- pub fn body_bytes(&self) -> Vec<u8> {
39
- let total_len: usize = self.chunks.iter().map(|c| c.len()).sum();
40
- let mut body = Vec::with_capacity(total_len);
41
- for chunk in &self.chunks {
42
- body.extend_from_slice(chunk);
43
- }
44
- body
45
- }
46
-
47
- /// Get the complete body as a string (lossy conversion)
48
- pub fn body_string(&self) -> String {
49
- String::from_utf8_lossy(&self.body_bytes()).to_string()
50
- }
51
- }
52
-
53
- /// Zap response types with auto-serialization
54
- #[derive(Debug)]
55
- pub enum ZapResponse {
56
- /// Plain text response
57
- Text(String),
58
- /// HTML response
59
- Html(String),
60
- /// JSON response (auto-serialized)
61
- Json(serde_json::Value),
62
- /// JSON response with custom status code
63
- JsonWithStatus(serde_json::Value, u16),
64
- /// Binary response
65
- Bytes(Bytes),
66
- /// File response
67
- File(PathBuf),
68
- /// Custom response with full control
69
- Custom(Response),
70
- /// Redirect response
71
- Redirect(String),
72
- /// Empty response with status code
73
- Status(StatusCode),
74
- /// Streaming response (collected chunks)
75
- Stream(StreamingResponse),
76
- }
77
-
78
- /// JSON response wrapper for auto-serialization
79
- #[derive(Debug)]
80
- pub struct Json<T>(pub T);
81
-
82
- impl<T: Serialize> From<Json<T>> for ZapResponse {
83
- fn from(json: Json<T>) -> Self {
84
- match serde_json::to_value(json.0) {
85
- Ok(value) => ZapResponse::Json(value),
86
- Err(_) => ZapResponse::Custom(
87
- Response::internal_server_error("Failed to serialize JSON"),
88
- ),
89
- }
90
- }
91
- }
92
-
93
- impl ZapResponse {
94
- /// Convert ZapResponse to hyper Response
95
- pub fn to_hyper_response(&self) -> hyper::Response<String> {
96
- match self {
97
- ZapResponse::Text(text) => hyper::Response::builder()
98
- .status(200)
99
- .header("Content-Type", "text/plain; charset=utf-8")
100
- .body(text.clone())
101
- .unwrap(),
102
- ZapResponse::Html(html) => hyper::Response::builder()
103
- .status(200)
104
- .header("Content-Type", "text/html; charset=utf-8")
105
- .body(html.clone())
106
- .unwrap(),
107
- ZapResponse::Json(json) => {
108
- let body = serde_json::to_string(json).unwrap_or_else(|_| {
109
- r#"{"error": "Failed to serialize JSON"}"#.to_string()
110
- });
111
- hyper::Response::builder()
112
- .status(200)
113
- .header("Content-Type", "application/json")
114
- .body(body)
115
- .unwrap()
116
- }
117
- ZapResponse::JsonWithStatus(json, status) => {
118
- let body = serde_json::to_string(json).unwrap_or_else(|_| {
119
- r#"{"error": "Failed to serialize JSON"}"#.to_string()
120
- });
121
- hyper::Response::builder()
122
- .status(*status)
123
- .header("Content-Type", "application/json")
124
- .body(body)
125
- .unwrap()
126
- }
127
- ZapResponse::Bytes(bytes) => hyper::Response::builder()
128
- .status(200)
129
- .header("Content-Type", "application/octet-stream")
130
- .body(String::from_utf8_lossy(bytes).to_string())
131
- .unwrap(),
132
- ZapResponse::Custom(response) => {
133
- let status = response.status.as_u16();
134
- let mut builder = hyper::Response::builder().status(status);
135
-
136
- for (key, value) in &response.headers {
137
- builder = builder.header(key, value);
138
- }
139
-
140
- let body = match &response.body {
141
- ResponseBody::Empty => String::new(),
142
- ResponseBody::Text(text) => text.clone(),
143
- ResponseBody::Bytes(bytes) => {
144
- String::from_utf8_lossy(bytes).to_string()
145
- }
146
- };
147
-
148
- builder.body(body).unwrap()
149
- }
150
- ZapResponse::Redirect(location) => hyper::Response::builder()
151
- .status(302)
152
- .header("Location", location)
153
- .body(String::new())
154
- .unwrap(),
155
- ZapResponse::Status(status) => hyper::Response::builder()
156
- .status(status.as_u16())
157
- .body(String::new())
158
- .unwrap(),
159
- ZapResponse::File(_path) => {
160
- // File serving would be implemented here
161
- // For now, return not implemented
162
- hyper::Response::builder()
163
- .status(501)
164
- .body("File serving not yet implemented".to_string())
165
- .unwrap()
166
- }
167
- ZapResponse::Stream(stream_response) => {
168
- let mut builder = hyper::Response::builder()
169
- .status(stream_response.status);
170
-
171
- // Add all headers from the streaming response
172
- for (key, value) in &stream_response.headers {
173
- builder = builder.header(key, value);
174
- }
175
-
176
- // Convert chunks to body
177
- let body = stream_response.body_string();
178
- builder.body(body).unwrap()
179
- }
180
- }
181
- }
182
- }
package/src/rpc.js DELETED
@@ -1,14 +0,0 @@
1
- /**
2
- * @zap-js/server/rpc
3
- *
4
- * RPC client for server communication
5
- */
6
-
7
- import { rpcCall } from '../../client/internal/runtime/src/rpc-client.js';
8
-
9
- // RPC object with call method
10
- const rpc = {
11
- call: rpcCall,
12
- };
13
-
14
- export default rpc;