1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
//! Reads the Vite IPC endpoint from the environment, once at startup.
//!
//! One responsibility: resolve `ARCATURE_VITE_IPC` to an [`IpcEndpoint`] at
//! pipeline-assembly time. This is the resolved-configuration seam for the
//! dev proxy — the env var is read **once** (when [`endpoint_from_env`] is
//! called during `into_service`), never per-request (AGENTS.md §21:
//! configuration is explicit and resolved; do not read environment variables
//! inside request handling). The resulting `Option<IpcEndpoint>` is stored
//! in the [`crate::dev_proxy::DevProxyLayer`] for the lifetime of the server.
//!
//! # The env var
//!
//! `arc dev` sets `ARCATURE_VITE_IPC` to the process-private IPC path it
//! created for Vite's `middlewareMode` server (Unix: a socket file under a
//! per-process temp dir; Windows: a `\\.\pipe\arcature-vite-<pid>` name).
//! When the var is unset (production, or `arc dev` not running), the dev
//! proxy is inactive — the layer is a zero-overhead pass-through.
//!
//! # Security
//!
//! The path is process-private and per-invocation; it is never
//! attacker-controlled. We do not validate the path's existence here
//! (connect-time `NotFound` is the honest signal if Vite is not up yet).
//! See the AP2.1-3 security review.
use PathBuf;
use crateIpcEndpoint;
/// The environment variable consulted for the Vite IPC endpoint.
///
/// Set by `arc dev` to the IPC path Vite's `middlewareMode` server listens
/// on. Unset in production → the dev proxy is inactive.
pub const IPC_ENV: &str = "ARCATURE_VITE_IPC";
/// Resolve the Vite IPC endpoint from the environment.
///
/// Returns `Some(endpoint)` when `ARCATURE_VITE_IPC` is set to a non-empty
/// value, `None` otherwise. Called once at pipeline-assembly time
/// ([`crate::pipeline::assemble::into_service`]); the result is stored in
/// the [`crate::dev_proxy::DevProxyLayer`].
///
/// Delegates to [`parse_endpoint`] for the pure string→endpoint mapping;
/// this function is the thin env-reading wrapper (AGENTS.md §21: the env is
/// read once here, never per-request).
pub
/// Parse a raw env value into an [`IpcEndpoint`].
///
/// Pure function: `None` or an empty string yields `None`; any non-empty
/// string yields `Some(endpoint)`. Extracted from [`endpoint_from_env`] so
/// the parsing logic is testable without mutating the process environment
/// (which is `unsafe` in Rust 2024 and forbidden by `#![forbid(unsafe_code)]`).
pub