create-ekka-desktop-app 0.2.2 → 0.2.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-ekka-desktop-app",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Create an EKKA desktop app with built-in demo backend. No setup required.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -10,6 +10,7 @@ edition = "2021"
10
10
 
11
11
  [build-dependencies]
12
12
  tauri-build = { version = "2", features = [] }
13
+ dotenvy = "0.15"
13
14
 
14
15
  [dependencies]
15
16
  tauri = { version = "2", features = [] }
@@ -1,3 +1,49 @@
1
1
  fn main() {
2
+ // Rerun if env files change (check both src-tauri and project root)
3
+ println!("cargo:rerun-if-changed=.env");
4
+ println!("cargo:rerun-if-changed=.env.local");
5
+ println!("cargo:rerun-if-changed=../.env");
6
+ println!("cargo:rerun-if-changed=../.env.local");
7
+
8
+ // Load env files: try src-tauri first, then project root
9
+ // .env.local takes precedence over .env
10
+ let _ = dotenvy::from_filename(".env.local");
11
+ let _ = dotenvy::from_filename(".env");
12
+ let _ = dotenvy::from_filename("../.env.local");
13
+ let _ = dotenvy::from_filename("../.env");
14
+
15
+ // EKKA_ENGINE_URL is required at build time
16
+ let engine_url = std::env::var("EKKA_ENGINE_URL").unwrap_or_else(|_| {
17
+ panic!(
18
+ "\n\n\
19
+ ╔══════════════════════════════════════════════════════════════════╗\n\
20
+ ║ BUILD ERROR: EKKA_ENGINE_URL is not set ║\n\
21
+ ╠══════════════════════════════════════════════════════════════════╣\n\
22
+ ║ Add EKKA_ENGINE_URL to .env.local or .env before building: ║\n\
23
+ ║ ║\n\
24
+ ║ echo 'EKKA_ENGINE_URL=https://api.ekka.ai' >> .env.local ║\n\
25
+ ║ ║\n\
26
+ ╚══════════════════════════════════════════════════════════════════╝\n\n"
27
+ )
28
+ });
29
+
30
+ if engine_url.trim().is_empty() {
31
+ panic!(
32
+ "\n\n\
33
+ ╔══════════════════════════════════════════════════════════════════╗\n\
34
+ ║ BUILD ERROR: EKKA_ENGINE_URL is empty ║\n\
35
+ ╠══════════════════════════════════════════════════════════════════╣\n\
36
+ ║ Set a valid URL in .env.local or .env: ║\n\
37
+ ║ ║\n\
38
+ ║ EKKA_ENGINE_URL=https://api.ekka.ai ║\n\
39
+ ║ ║\n\
40
+ ╚══════════════════════════════════════════════════════════════════╝\n\n"
41
+ )
42
+ }
43
+
44
+ // Bake EKKA_ENGINE_URL into the binary at compile time
45
+ println!("cargo:rustc-env=EKKA_ENGINE_URL={}", engine_url);
46
+
47
+ // Continue with tauri build
2
48
  tauri_build::build()
3
49
  }
@@ -455,9 +455,10 @@ fn handle_node_credentials_clear() -> EngineResponse {
455
455
  fn handle_runner_task_stats(state: &EngineState) -> EngineResponse {
456
456
  use crate::state::NodeAuthState;
457
457
 
458
- // Get engine URL (needed for both auth and stats request)
459
- let engine_url = std::env::var("EKKA_ENGINE_URL")
460
- .unwrap_or_else(|_| "https://api.ekka.ai".to_string());
458
+ // Get engine URL (baked at build time)
459
+ let engine_url = option_env!("EKKA_ENGINE_URL")
460
+ .unwrap_or("https://api.ekka.ai")
461
+ .to_string();
461
462
 
462
463
  // Get node auth token for Authorization header
463
464
  let node_token = match state.get_node_auth_token() {
@@ -819,8 +820,9 @@ fn handle_bootstrap_node_session(payload: &Value, state: &EngineState) -> Engine
819
820
  if start_runner {
820
821
  // Build runner config from node auth token
821
822
  let runner_config = node_auth::NodeSessionRunnerConfig {
822
- engine_url: std::env::var("EKKA_ENGINE_URL")
823
- .or_else(|_| std::env::var("ENGINE_URL"))
823
+ engine_url: option_env!("EKKA_ENGINE_URL")
824
+ .map(|s| s.to_string())
825
+ .or_else(|| std::env::var("ENGINE_URL").ok())
824
826
  .unwrap_or_default(),
825
827
  node_url: std::env::var("NODE_URL").unwrap_or_else(|_| "http://127.0.0.1:7777".to_string()),
826
828
  session_token: node_token.token.clone(),
@@ -913,8 +915,9 @@ fn build_security_headers(jwt: Option<&str>, module: &str, action: &str) -> Vec<
913
915
 
914
916
  /// Create a workflow run (POST /engine/workflow-runs)
915
917
  fn handle_workflow_runs_create(payload: &Value) -> EngineResponse {
916
- let engine_url = std::env::var("EKKA_ENGINE_URL")
917
- .unwrap_or_else(|_| "http://localhost:3200".to_string());
918
+ let engine_url = option_env!("EKKA_ENGINE_URL")
919
+ .unwrap_or("http://localhost:3200")
920
+ .to_string();
918
921
 
919
922
  // Extract request body
920
923
  let request = match payload.get("request") {
@@ -974,8 +977,9 @@ fn handle_workflow_runs_create(payload: &Value) -> EngineResponse {
974
977
 
975
978
  /// Get a workflow run (GET /engine/workflow-runs/{id})
976
979
  fn handle_workflow_runs_get(payload: &Value) -> EngineResponse {
977
- let engine_url = std::env::var("EKKA_ENGINE_URL")
978
- .unwrap_or_else(|_| "http://localhost:3200".to_string());
980
+ let engine_url = option_env!("EKKA_ENGINE_URL")
981
+ .unwrap_or("http://localhost:3200")
982
+ .to_string();
979
983
 
980
984
  // Extract workflow run ID
981
985
  let id = match payload.get("id").and_then(|v| v.as_str()) {
@@ -46,9 +46,9 @@ fn build_engine_env() -> Result<Vec<(&'static str, String)>, &'static str> {
46
46
  // EKKA_RUNNER_MODE=engine (always set)
47
47
  env.push(("EKKA_RUNNER_MODE", "engine".to_string()));
48
48
 
49
- // EKKA_ENGINE_URL - pass through from process env or use default
50
- if let Ok(url) = std::env::var("EKKA_ENGINE_URL") {
51
- env.push(("EKKA_ENGINE_URL", url));
49
+ // EKKA_ENGINE_URL - baked at build time
50
+ if let Some(url) = option_env!("EKKA_ENGINE_URL") {
51
+ env.push(("EKKA_ENGINE_URL", url.to_string()));
52
52
  }
53
53
 
54
54
  // EKKA_INTERNAL_SERVICE_KEY - required for engine mode
@@ -74,6 +74,14 @@ fn main() {
74
74
  "Required security env vars"
75
75
  );
76
76
 
77
+ // Log build-time baked engine URL presence (not the URL itself)
78
+ let engine_url_baked = option_env!("EKKA_ENGINE_URL").is_some();
79
+ tracing::info!(
80
+ op = "desktop.engine_url.baked",
81
+ present = engine_url_baked,
82
+ "EKKA_ENGINE_URL baked at build time"
83
+ );
84
+
77
85
  // Check for stored node credentials (vault-backed)
78
86
  let has_creds = node_credentials::has_credentials();
79
87
 
@@ -112,13 +120,14 @@ fn main() {
112
120
  }
113
121
 
114
122
  // Authenticate node with server before spawning engine
115
- let engine_url = match std::env::var("EKKA_ENGINE_URL") {
116
- Ok(url) => url,
117
- Err(_) => {
123
+ // EKKA_ENGINE_URL is baked at build time via build.rs
124
+ let engine_url = match option_env!("EKKA_ENGINE_URL") {
125
+ Some(url) => url.to_string(),
126
+ None => {
118
127
  tracing::warn!(
119
128
  op = "desktop.engine.start.blocked",
120
129
  reason = "missing_engine_url",
121
- "Engine start blocked - EKKA_ENGINE_URL not set"
130
+ "Engine start blocked - EKKA_ENGINE_URL not baked at build time"
122
131
  );
123
132
  return;
124
133
  }
@@ -770,9 +770,11 @@ pub struct NodeSessionRunnerConfig {
770
770
 
771
771
  impl NodeSessionRunnerConfig {
772
772
  pub fn from_session(session: &NodeSession, node_id: Uuid) -> Result<Self, String> {
773
- let engine_url = std::env::var("ENGINE_URL")
774
- .or_else(|_| std::env::var("EKKA_ENGINE_URL"))
775
- .map_err(|_| "ENGINE_URL or EKKA_ENGINE_URL required")?;
773
+ // EKKA_ENGINE_URL baked at build time, ENGINE_URL as runtime fallback
774
+ let engine_url = option_env!("EKKA_ENGINE_URL")
775
+ .map(|s| s.to_string())
776
+ .or_else(|| std::env::var("ENGINE_URL").ok())
777
+ .ok_or("EKKA_ENGINE_URL not baked at build time and ENGINE_URL not set")?;
776
778
 
777
779
  let node_url = std::env::var("NODE_URL").unwrap_or_else(|_| "http://127.0.0.1:7777".to_string());
778
780
 
@@ -80,13 +80,13 @@ pub fn handle_grant(state: &EngineState) -> EngineResponse {
80
80
  None => return EngineResponse::err("MARKER_INVALID", "Marker missing instance_id"),
81
81
  };
82
82
 
83
- // 4. Get engine URL
84
- let engine_url = match std::env::var("EKKA_ENGINE_URL") {
85
- Ok(u) => u,
86
- Err(_) => {
83
+ // 4. Get engine URL (baked at build time)
84
+ let engine_url = match option_env!("EKKA_ENGINE_URL") {
85
+ Some(u) => u,
86
+ None => {
87
87
  return EngineResponse::err(
88
88
  "ENGINE_NOT_CONFIGURED",
89
- "EKKA_ENGINE_URL not set. HOME grant requires online engine.",
89
+ "EKKA_ENGINE_URL not baked at build time. Rebuild with EKKA_ENGINE_URL set.",
90
90
  )
91
91
  }
92
92
  };
@@ -179,7 +179,7 @@ impl Default for RunnerStatus {
179
179
  enabled: false,
180
180
  state: RunnerLoopState::Stopped,
181
181
  runner_id: None,
182
- engine_url: std::env::var("EKKA_ENGINE_URL").ok(),
182
+ engine_url: option_env!("EKKA_ENGINE_URL").map(|s| s.to_string()),
183
183
  last_poll_at: None,
184
184
  last_claim_at: None,
185
185
  last_complete_at: None,
@@ -259,9 +259,10 @@ impl RunnerState {
259
259
  s.enabled = true;
260
260
  s.state = RunnerLoopState::Running;
261
261
  s.runner_id = Some(runner_id.to_string());
262
- s.engine_url = std::env::var("EKKA_ENGINE_URL")
263
- .or_else(|_| std::env::var("ENGINE_URL"))
264
- .ok();
262
+ // EKKA_ENGINE_URL baked at build time, ENGINE_URL as runtime fallback
263
+ s.engine_url = option_env!("EKKA_ENGINE_URL")
264
+ .map(|s| s.to_string())
265
+ .or_else(|| std::env::var("ENGINE_URL").ok());
265
266
  s.last_error = None;
266
267
  });
267
268
  }
@@ -511,11 +512,11 @@ impl GrantIssuer for EngineHttpGrantIssuer {
511
512
  EkkaError::new(ops::codes::NOT_AUTHENTICATED, "Must login before requesting grant")
512
513
  })?;
513
514
 
514
- // Get engine URL
515
- let engine_url = std::env::var("EKKA_ENGINE_URL").map_err(|_| {
515
+ // Get engine URL (baked at build time)
516
+ let engine_url = option_env!("EKKA_ENGINE_URL").ok_or_else(|| {
516
517
  EkkaError::new(
517
518
  ops::codes::ENGINE_ERROR,
518
- "EKKA_ENGINE_URL not set. Grant requires online engine.",
519
+ "EKKA_ENGINE_URL not baked at build time. Rebuild with EKKA_ENGINE_URL set.",
519
520
  )
520
521
  })?;
521
522
 
@@ -613,10 +614,10 @@ impl GrantIssuer for EngineHttpGrantIssuer {
613
614
  EkkaError::new(ops::codes::NOT_AUTHENTICATED, "Must login to revoke grant")
614
615
  })?;
615
616
 
616
- // Get engine URL (optional - revoke is best effort)
617
- let engine_url = match std::env::var("EKKA_ENGINE_URL") {
618
- Ok(url) => url,
619
- Err(_) => return Ok(()), // No engine, just return success
617
+ // Get engine URL (baked at build time, optional - revoke is best effort)
618
+ let engine_url = match option_env!("EKKA_ENGINE_URL") {
619
+ Some(url) => url,
620
+ None => return Ok(()), // No engine baked, just return success
620
621
  };
621
622
 
622
623
  // Make revoke request (best effort)