@devaloop/devalang 0.0.1-alpha.13 → 0.0.1-alpha.14

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 (50) hide show
  1. package/.devalang +8 -9
  2. package/Cargo.toml +58 -54
  3. package/README.md +36 -21
  4. package/docs/CHANGELOG.md +40 -2
  5. package/docs/CONTRIBUTING.md +1 -0
  6. package/docs/ROADMAP.md +2 -2
  7. package/docs/TODO.md +5 -4
  8. package/examples/bank.deva +2 -4
  9. package/examples/function.deva +15 -0
  10. package/examples/index.deva +25 -11
  11. package/out-tsc/bin/devalang.exe +0 -0
  12. package/package.json +6 -6
  13. package/project-version.json +3 -3
  14. package/rust/cli/bank.rs +2 -1
  15. package/rust/cli/build.rs +69 -30
  16. package/rust/cli/check.rs +45 -5
  17. package/rust/cli/driver.rs +40 -28
  18. package/rust/cli/install.rs +22 -7
  19. package/rust/cli/login.rs +134 -0
  20. package/rust/cli/mod.rs +2 -1
  21. package/rust/cli/play.rs +44 -19
  22. package/rust/common/api.rs +8 -0
  23. package/rust/common/cdn.rs +2 -5
  24. package/rust/common/mod.rs +3 -1
  25. package/rust/common/sso.rs +8 -0
  26. package/rust/config/driver.rs +19 -1
  27. package/rust/config/loader.rs +56 -10
  28. package/rust/core/audio/engine.rs +152 -42
  29. package/rust/core/audio/interpreter/arrow_call.rs +34 -15
  30. package/rust/core/audio/interpreter/call.rs +2 -2
  31. package/rust/core/audio/interpreter/driver.rs +19 -14
  32. package/rust/core/audio/interpreter/spawn.rs +2 -2
  33. package/rust/core/builder/mod.rs +11 -6
  34. package/rust/core/lexer/handler/indent.rs +16 -2
  35. package/rust/core/lexer/token.rs +1 -0
  36. package/rust/core/mod.rs +2 -1
  37. package/rust/core/parser/driver.rs +46 -5
  38. package/rust/core/parser/handler/arrow_call.rs +78 -18
  39. package/rust/core/parser/handler/bank.rs +35 -7
  40. package/rust/core/parser/handler/dot.rs +43 -22
  41. package/rust/core/plugin/loader.rs +48 -0
  42. package/rust/core/plugin/mod.rs +1 -0
  43. package/rust/core/preprocessor/loader.rs +6 -4
  44. package/rust/installer/addon.rs +80 -0
  45. package/rust/installer/bank.rs +24 -14
  46. package/rust/installer/mod.rs +4 -1
  47. package/rust/installer/plugin.rs +55 -0
  48. package/rust/main.rs +32 -9
  49. package/rust/utils/logger.rs +16 -0
  50. package/rust/utils/spinner.rs +2 -4
package/rust/cli/check.rs CHANGED
@@ -1,6 +1,12 @@
1
1
  use crate::{
2
2
  config::driver::Config,
3
3
  core::{
4
+ debugger::{
5
+ lexer::write_lexer_log_file,
6
+ module::{ write_module_function_log_file, write_module_variable_log_file },
7
+ preprocessor::write_preprocessor_log_file,
8
+ store::{ write_function_log_file, write_variables_log_file },
9
+ },
4
10
  preprocessor::loader::ModuleLoader,
5
11
  store::global::GlobalStore,
6
12
  utils::path::{ find_entry_file, normalize_path },
@@ -19,7 +25,8 @@ pub fn handle_check_command(
19
25
  config: Option<Config>,
20
26
  entry: Option<String>,
21
27
  output: Option<String>,
22
- watch: bool
28
+ watch: bool,
29
+ debug: bool
23
30
  ) {
24
31
  let fetched_entry = if entry.is_none() {
25
32
  config
@@ -75,7 +82,7 @@ pub fn handle_check_command(
75
82
 
76
83
  // SECTION Begin check
77
84
  if fetched_watch {
78
- begin_check(entry_file.clone(), fetched_output.clone());
85
+ begin_check(entry_file.clone(), fetched_output.clone(), debug);
79
86
 
80
87
  logger.log_message(
81
88
  LogLevel::Watcher,
@@ -85,14 +92,14 @@ pub fn handle_check_command(
85
92
  watch_directory(entry_file.clone(), move || {
86
93
  logger.log_message(LogLevel::Watcher, "Detected changes, re-checking...");
87
94
 
88
- begin_check(entry_file.clone(), fetched_output.clone());
95
+ begin_check(entry_file.clone(), fetched_output.clone(), debug);
89
96
  }).unwrap();
90
97
  } else {
91
- begin_check(entry_file.clone(), fetched_output.clone());
98
+ begin_check(entry_file.clone(), fetched_output.clone(), debug);
92
99
  }
93
100
  }
94
101
 
95
- fn begin_check(entry: String, output: String) {
102
+ fn begin_check(entry: String, output: String, debug: bool) {
96
103
  let spinner = with_spinner("Checking...", || {
97
104
  thread::sleep(Duration::from_millis(800));
98
105
  });
@@ -116,6 +123,38 @@ fn begin_check(entry: String, output: String) {
116
123
  logger.log_message(LogLevel::Info, &format!("- {}", module_name));
117
124
  }
118
125
 
126
+ if debug {
127
+ for (module_path, module) in global_store.modules.clone() {
128
+ write_module_variable_log_file(
129
+ &normalized_output_dir,
130
+ &module_path,
131
+ &module.variable_table
132
+ );
133
+ write_module_function_log_file(
134
+ &normalized_output_dir,
135
+ &module_path,
136
+ &module.function_table
137
+ );
138
+ }
139
+
140
+ write_lexer_log_file(&normalized_output_dir, "lexer_tokens.log", modules.0.clone());
141
+ write_preprocessor_log_file(
142
+ &normalized_output_dir,
143
+ "resolved_statements.log",
144
+ modules.1.clone()
145
+ );
146
+ write_variables_log_file(
147
+ &normalized_output_dir,
148
+ "global_variables.log",
149
+ global_store.variables.clone()
150
+ );
151
+ write_function_log_file(
152
+ &normalized_output_dir,
153
+ "global_functions.log",
154
+ global_store.functions.clone()
155
+ );
156
+ }
157
+
119
158
  let mut all_errors = Vec::new();
120
159
  for (_, statements) in &modules.1 {
121
160
  all_errors.extend(collect_errors_recursively(statements));
@@ -136,5 +175,6 @@ fn begin_check(entry: String, output: String) {
136
175
  normalized_output_dir
137
176
  );
138
177
 
178
+ spinner.finish_and_clear();
139
179
  logger.log_message(LogLevel::Success, &success_message);
140
180
  }
@@ -21,6 +21,14 @@ pub enum InstallCommand {
21
21
  Bank {
22
22
  name: String,
23
23
  },
24
+ /// Installs a plugin.
25
+ Plugin {
26
+ name: String,
27
+ },
28
+ /// Installs a preset.
29
+ Preset {
30
+ name: String,
31
+ },
24
32
  }
25
33
 
26
34
  #[derive(Subcommand)]
@@ -103,10 +111,12 @@ pub enum Commands {
103
111
  /// - `entry` - The entry point of the program to build. Defaults to "./src".
104
112
  /// - `output` - The directory where the output files will be generated. Defaults to "./output".
105
113
  /// - `watch` - Whether to watch for changes and rebuild. Defaults to "true".
114
+ /// - `debug` - Whether to print debug information. Defaults to "false".
115
+ /// - `compress` - Whether to compress the output files. Defaults to "false".
106
116
  ///
107
117
  /// ### Example
108
118
  /// ```bash
109
- /// devalang build --entry ./src --output ./output --watch true
119
+ /// devalang build --entry ./src --output ./output --watch true --debug false --compress false
110
120
  /// ```
111
121
  ///
112
122
  Build {
@@ -128,19 +138,6 @@ pub enum Commands {
128
138
  ///
129
139
  watch: bool,
130
140
 
131
- #[arg(long, default_value = "real-time")]
132
- /// The mode of compilation.
133
- ///
134
- /// ### Default value
135
- /// - `real-time`
136
- ///
137
- /// ### Possible values
138
- /// - `real-time` - Compiles files as soon as possible.
139
- /// - `batch` - Compiles files one by one.
140
- /// - `check` - Analyzes the code without compiling it.
141
- ///
142
- compilation_mode: String,
143
-
144
141
  #[arg(short, long, default_value_t = false)]
145
142
  /// Whether to print debug information.
146
143
  ///
@@ -164,9 +161,13 @@ pub enum Commands {
164
161
  /// - `entry` - The entry point of the program to analyze. Defaults to "./src".
165
162
  /// - `output` - The directory where the output files will be generated. Defaults to "./output".
166
163
  /// - `watch` - Whether to watch for changes and re-analyze. Defaults to "true".
167
- /// - `compilation_mode` - The mode of compilation. Defaults to "real-time".
168
164
  /// - `debug` - Whether to print debug information. Defaults to "false".
169
165
  ///
166
+ /// ### Example
167
+ /// ```bash
168
+ /// devalang check --entry ./src --output ./output --watch true --debug false
169
+ /// ```
170
+ ///
170
171
  Check {
171
172
  #[arg(short, long)]
172
173
  /// The entry point of the program to analyze.
@@ -184,19 +185,6 @@ pub enum Commands {
184
185
  ///
185
186
  watch: bool,
186
187
 
187
- #[arg(short, long, default_value = "real-time")]
188
- /// The mode of compilation.
189
- ///
190
- /// ### Default value
191
- /// - `real-time`
192
- ///
193
- /// ### Possible values
194
- /// - `real-time` - Analyzes files as soon as possible.
195
- /// - `batch` - Analyzes files one by one.
196
- /// - `check` - Analyzes the code without compiling it.
197
- ///
198
- compilation_mode: String,
199
-
200
188
  #[arg(short, long, default_value_t = false)]
201
189
  /// Whether to print debug information.
202
190
  ///
@@ -213,6 +201,14 @@ pub enum Commands {
213
201
  /// - `output` - The directory where the output files will be generated. Defaults to "./output".
214
202
  /// - `watch` - Whether to watch for changes and re-play. Defaults to "false".
215
203
  /// - `repeat` - Whether to replay the program after it finishes. Defaults to "false".
204
+ /// - `debug` - Whether to print debug information. Defaults to "false".
205
+ ///
206
+ /// Note: `--repeat` and `--watch` cannot be used together. Instead use `repeat` to watch for changes and replay the program.
207
+ ///
208
+ /// ### Example
209
+ /// ```bash
210
+ /// devalang play --entry ./src --output ./output --repeat true --debug false
211
+ /// ```
216
212
  ///
217
213
  Play {
218
214
  #[arg(short, long)]
@@ -238,6 +234,14 @@ pub enum Commands {
238
234
  /// - `false`
239
235
  ///
240
236
  repeat: bool,
237
+
238
+ #[arg(short, long, default_value_t = false)]
239
+ /// Whether to print debug information.
240
+ ///
241
+ /// ### Default value
242
+ /// - `false`
243
+ ///
244
+ debug: bool,
241
245
  },
242
246
 
243
247
  /// Update the Devalang CLI to the latest version.
@@ -277,4 +281,12 @@ pub enum Commands {
277
281
  #[command(subcommand)]
278
282
  command: BankCommand,
279
283
  },
284
+
285
+ /// Log in to your Devaloop account.
286
+ ///
287
+ Login {},
288
+
289
+ /// Log out of your Devaloop account.
290
+ ///
291
+ Logout {},
280
292
  }
@@ -1,16 +1,31 @@
1
- use crate::installer::bank::install_bank;
1
+ use crate::installer::addon::{ install_addon, AddonType };
2
2
 
3
+ /// Handles the installation command for a given addon type and name.
3
4
  #[cfg(feature = "cli")]
4
- pub async fn handle_install_bank_command(name: String) -> Result<(), String> {
5
+ pub async fn handle_install_command(name: String, addon_type: AddonType) -> Result<(), String> {
6
+ use crate::utils::{ logger::{ LogLevel, Logger }, spinner::with_spinner };
7
+ use std::{ thread, time::Duration };
8
+
9
+ let logger = Logger::new();
5
10
  let deva_dir = std::path::Path::new("./.deva/");
6
11
 
7
- println!("⬇️ Installing bank '{}'...", name);
8
- println!("📂 Target directory: {}", deva_dir.display());
12
+ let spinner = with_spinner("Installing...", || {
13
+ thread::sleep(Duration::from_millis(800));
14
+ });
9
15
 
10
- if let Err(e) = install_bank(name.as_str(), deva_dir).await {
11
- eprintln!("❌ Error installing bank '{}': {}", name, e);
16
+ if let Err(e) = install_addon(addon_type.clone(), name.as_str(), deva_dir).await {
17
+ spinner.finish_and_clear();
18
+ logger.log_message_with_trace(
19
+ LogLevel::Error,
20
+ &format!("Error installing {:?} '{}'", addon_type, name),
21
+ vec![&e]
22
+ );
12
23
  } else {
13
- println!("✅ Bank '{}' installed successfully!", name);
24
+ spinner.finish_and_clear();
25
+ logger.log_message(
26
+ LogLevel::Success,
27
+ &format!("{:?} '{}' installed successfully!", addon_type, name)
28
+ );
14
29
  }
15
30
 
16
31
  Ok(())
@@ -0,0 +1,134 @@
1
+ use std::fs;
2
+ use tiny_http::{ Server, Response };
3
+ use webbrowser;
4
+ use serde::{ Serialize, Deserialize };
5
+ use dirs::home_dir;
6
+ use crate::common::sso::get_sso_url;
7
+ use std::{ thread, time::Duration };
8
+ use tiny_http::Header;
9
+ use std::str::FromStr;
10
+
11
+ #[derive(Serialize, Deserialize)]
12
+ struct UserConfig {
13
+ token: String,
14
+ }
15
+
16
+ /// Handle the login command
17
+ /// This function initiates the login process by opening the browser and waiting for the callback.
18
+ #[cfg(feature = "cli")]
19
+ pub async fn handle_login_command() -> Result<(), String> {
20
+ use crate::utils::spinner::with_spinner;
21
+ use crate::utils::logger::Logger;
22
+ use crate::utils::logger::LogLevel;
23
+
24
+ let logger = Logger::new();
25
+
26
+ let mut listener_port = 7878;
27
+
28
+ let test_port_already_in_use = format!("127.0.0.1:{}", listener_port);
29
+ while std::net::TcpListener::bind(&test_port_already_in_use).is_err() {
30
+ listener_port += 1;
31
+ }
32
+
33
+ let redirect_uri = format!("http://127.0.0.1:{}/callback", listener_port);
34
+ let login_url = format!(
35
+ "{}/?response_type=code&referer=cli&redirect_uri={}",
36
+ get_sso_url(),
37
+ redirect_uri
38
+ );
39
+
40
+ if webbrowser::open(&login_url).is_ok() {
41
+ logger.log_message(LogLevel::Info, "Opening browser for login...");
42
+ logger.log_message(
43
+ LogLevel::Info,
44
+ &format!("If the browser does not open, please visit the following URL: {}", login_url)
45
+ );
46
+ } else {
47
+ logger.log_message(
48
+ LogLevel::Info,
49
+ "Please open the following URL in your browser to login:"
50
+ );
51
+ logger.log_message(LogLevel::Info, &login_url);
52
+ }
53
+
54
+ let server = Server::http(format!("127.0.0.1:{}", listener_port)).unwrap();
55
+
56
+ let spinner = with_spinner("Waiting for authentication...", || {
57
+ thread::sleep(Duration::from_millis(800));
58
+ });
59
+
60
+ for request in server.incoming_requests() {
61
+ let query = request.url().to_string();
62
+ if request.url().starts_with("/callback") {
63
+ if query.contains("session=") || query.contains("error=") {
64
+ let token = query.split("session=").nth(1).unwrap_or("").to_string();
65
+
66
+ if token.len() > 0 {
67
+ let response_html =
68
+ r#"
69
+ <html>
70
+ <body>
71
+ <h1>Authentication Successful</h1>
72
+ <h2>You can now close this window.</h2>
73
+ </body>
74
+ </html>
75
+ "#;
76
+
77
+ let response = Response::from_string(response_html)
78
+ .with_status_code(200)
79
+ .with_header(Header::from_str("Content-Type: text/html").unwrap());
80
+
81
+ request.respond(response).unwrap();
82
+
83
+ save_token(&token);
84
+
85
+ spinner.finish_and_clear();
86
+
87
+ logger.log_message(
88
+ LogLevel::Success,
89
+ "Authentication successful. Token saved to ~/.devalang/session_token.json"
90
+ );
91
+
92
+ break;
93
+ } else {
94
+ spinner.finish_and_clear();
95
+ logger.log_message(LogLevel::Error, "Invalid session token.");
96
+ request.respond(Response::from_string("Invalid session token.")).unwrap();
97
+
98
+ break;
99
+ }
100
+ } else {
101
+ println!("Invalid callback: {}", request.url());
102
+
103
+ spinner.finish_and_clear();
104
+ logger.log_message(LogLevel::Error, "Invalid callback.");
105
+ request.respond(Response::from_string("Invalid callback.")).unwrap();
106
+
107
+ break;
108
+ }
109
+ } else if request.url().starts_with("/favicon.ico") {
110
+ // Ignore favicon requests
111
+ } else {
112
+ spinner.finish_and_clear();
113
+ logger.log_message(LogLevel::Error, "Invalid request.");
114
+ request.respond(Response::from_string("Invalid request.")).unwrap();
115
+
116
+ break;
117
+ }
118
+ }
119
+
120
+ Ok(())
121
+ }
122
+
123
+ /// Save the session token to a file in the user's home directory
124
+ fn save_token(token: &str) {
125
+ let config = UserConfig { token: token.to_string() };
126
+ let json = serde_json::to_string(&config).unwrap();
127
+
128
+ let mut path = home_dir().unwrap();
129
+ path.push(".devalang");
130
+ fs::create_dir_all(&path).unwrap();
131
+
132
+ path.push("session_token.json");
133
+ fs::write(path, json).unwrap();
134
+ }
package/rust/cli/mod.rs CHANGED
@@ -7,4 +7,5 @@ pub mod template;
7
7
  pub mod play;
8
8
  pub mod install;
9
9
  pub mod bank;
10
- pub mod update;
10
+ pub mod update;
11
+ pub mod login;
package/rust/cli/play.rs CHANGED
@@ -1,13 +1,11 @@
1
1
  use crate::{
2
- core::{
2
+ config::driver::Config, core::{
3
3
  builder::Builder,
4
- debugger::{ lexer::write_lexer_log_file, preprocessor::write_preprocessor_log_file },
4
+ debugger::{ lexer::write_lexer_log_file, module::{write_module_function_log_file, write_module_variable_log_file}, preprocessor::write_preprocessor_log_file, store::{write_function_log_file, write_variables_log_file} },
5
5
  preprocessor::loader::ModuleLoader,
6
6
  store::global::GlobalStore,
7
7
  utils::path::{ find_entry_file, normalize_path },
8
- },
9
- config::driver::Config,
10
- utils::{ logger::{ LogLevel, Logger }, spinner::with_spinner, watcher::watch_directory },
8
+ }, utils::{ logger::{ LogLevel, Logger }, spinner::with_spinner, watcher::watch_directory }
11
9
  };
12
10
 
13
11
  use std::{ path::Path, sync::mpsc::channel, thread, time::Duration };
@@ -20,7 +18,8 @@ pub fn handle_play_command(
20
18
  entry: Option<String>,
21
19
  output: Option<String>,
22
20
  watch: bool,
23
- repeat: bool
21
+ repeat: bool,
22
+ debug: bool
24
23
  ) {
25
24
  use crate::core::audio::player::AudioPlayer;
26
25
 
@@ -76,7 +75,7 @@ pub fn handle_play_command(
76
75
  });
77
76
 
78
77
  // Main thread: build + play in a loop
79
- begin_play(&config, &entry_file, &output_path);
78
+ begin_play(&config, &entry_file, &output_path, debug);
80
79
  audio_player.play_file_once(&audio_file);
81
80
 
82
81
  logger.log_message(LogLevel::Watcher, "Watching for changes... Press Ctrl+C to exit.");
@@ -84,7 +83,7 @@ pub fn handle_play_command(
84
83
  while let Ok(_) = rx.recv() {
85
84
  logger.log_message(LogLevel::Watcher, "Change detected, rebuilding...");
86
85
 
87
- begin_play(&config, &entry_file, &output_path);
86
+ begin_play(&config, &entry_file, &output_path, debug);
88
87
 
89
88
  logger.log_message(LogLevel::Info, "🎵 Playback started (once mode)...");
90
89
 
@@ -92,7 +91,7 @@ pub fn handle_play_command(
92
91
  }
93
92
  } else if fetched_repeat {
94
93
  // Initial build to start from a clean slate
95
- begin_play(&config, &entry_file, &output_path);
94
+ begin_play(&config, &entry_file, &output_path, debug);
96
95
 
97
96
  logger.log_message(LogLevel::Info, "🎵 Playback started (repeat mode)...");
98
97
 
@@ -112,7 +111,7 @@ pub fn handle_play_command(
112
111
 
113
112
  // Rebuild in a separate thread
114
113
  std::thread::spawn(move || {
115
- begin_play(&config_clone, &entry_file, &output_path);
114
+ begin_play(&config_clone, &entry_file, &output_path, debug);
116
115
  });
117
116
 
118
117
  last_snapshot = current_snapshot;
@@ -126,7 +125,7 @@ pub fn handle_play_command(
126
125
  }
127
126
  } else {
128
127
  // Single execution
129
- begin_play(&config, &entry_file, &output_path);
128
+ begin_play(&config, &entry_file, &output_path, debug);
130
129
 
131
130
  logger.log_message(LogLevel::Info, "🎵 Playback started (once mode)...");
132
131
 
@@ -135,7 +134,7 @@ pub fn handle_play_command(
135
134
  }
136
135
  }
137
136
 
138
- fn begin_play(config: &Option<Config>, entry_file: &str, output: &str) {
137
+ fn begin_play(config: &Option<Config>, entry_file: &str, output: &str, debug: bool) {
139
138
  let spinner = with_spinner("Building...", || {
140
139
  thread::sleep(Duration::from_millis(800));
141
140
  });
@@ -149,16 +148,41 @@ fn begin_play(config: &Option<Config>, entry_file: &str, output: &str) {
149
148
  let (modules_tokens, modules_statements) = loader.load_all_modules(&mut global_store);
150
149
 
151
150
  // SECTION Write logs
152
- write_lexer_log_file(&normalized_output_dir, "lexer_tokens.log", modules_tokens.clone());
153
- write_preprocessor_log_file(
154
- &normalized_output_dir,
155
- "resolved_statements.log",
156
- modules_statements.clone()
157
- );
151
+ if debug {
152
+ for (module_path, module) in global_store.modules.clone() {
153
+ write_module_variable_log_file(
154
+ &normalized_output_dir,
155
+ &module_path,
156
+ &module.variable_table
157
+ );
158
+ write_module_function_log_file(
159
+ &normalized_output_dir,
160
+ &module_path,
161
+ &module.function_table
162
+ );
163
+ }
164
+
165
+ write_lexer_log_file(&normalized_output_dir, "lexer_tokens.log", modules_tokens.clone());
166
+ write_preprocessor_log_file(
167
+ &normalized_output_dir,
168
+ "resolved_statements.log",
169
+ modules_statements.clone()
170
+ );
171
+ write_variables_log_file(
172
+ &normalized_output_dir,
173
+ "global_variables.log",
174
+ global_store.variables.clone()
175
+ );
176
+ write_function_log_file(
177
+ &normalized_output_dir,
178
+ "global_functions.log",
179
+ global_store.functions.clone()
180
+ );
181
+ }
158
182
 
159
183
  // SECTION Building AST and Audio
160
184
  let builder = Builder::new();
161
- builder.build_ast(&modules_statements, &output);
185
+ builder.build_ast(&modules_statements, &output, false);
162
186
  builder.build_audio(&modules_statements, &output, &mut global_store);
163
187
 
164
188
  // SECTION Logging
@@ -169,6 +193,7 @@ fn begin_play(config: &Option<Config>, entry_file: &str, output: &str) {
169
193
  normalized_output_dir
170
194
  );
171
195
 
196
+ spinner.finish_and_clear();
172
197
  logger.log_message(LogLevel::Success, &success_message);
173
198
  }
174
199
 
@@ -0,0 +1,8 @@
1
+ pub fn get_api_url() -> String {
2
+ let api_url = std::env
3
+ ::var("API_URL")
4
+ .unwrap_or_else(|_| "https://api.devalang.com".to_string());
5
+ // .unwrap_or_else(|_| "http://127.0.0.1:8989".to_string());
6
+
7
+ api_url
8
+ }
@@ -2,10 +2,7 @@ pub fn get_cdn_url() -> String {
2
2
  let cdn_url = std::env
3
3
  ::var("CDN_URL")
4
4
  .unwrap_or_else(|_| "https://cdn.devalang.com".to_string());
5
+ // .unwrap_or_else(|_| "http://127.0.0.1:8888".to_string());
5
6
 
6
- if !cdn_url.ends_with('/') {
7
- format!("{}/", cdn_url)
8
- } else {
9
- cdn_url
10
- }
7
+ cdn_url
11
8
  }
@@ -1 +1,3 @@
1
- pub mod cdn;
1
+ pub mod cdn;
2
+ pub mod api;
3
+ pub mod sso;
@@ -0,0 +1,8 @@
1
+ pub fn get_sso_url() -> String {
2
+ let sso_url = std::env
3
+ ::var("SSO_URL")
4
+ .unwrap_or_else(|_| "https://sso.devalang.com".to_string());
5
+ // .unwrap_or_else(|_| "http://localhost:5174".to_string());
6
+
7
+ sso_url
8
+ }
@@ -1,9 +1,12 @@
1
+ use std::collections::HashMap;
2
+
1
3
  use serde::{ Deserialize, Serialize };
2
4
 
3
5
  #[derive(Debug, Deserialize, Clone, Serialize)]
4
6
  pub struct Config {
5
7
  pub defaults: ConfigDefaults,
6
8
  pub banks: Option<Vec<BankEntry>>,
9
+ pub plugins: Option<Vec<PluginEntry>>,
7
10
  }
8
11
 
9
12
  #[derive(Debug, Deserialize, Clone, Serialize)]
@@ -14,11 +17,24 @@ pub struct ConfigDefaults {
14
17
  pub repeat: Option<bool>,
15
18
  }
16
19
 
20
+ #[derive(Debug, Deserialize, Clone, Serialize)]
21
+ pub struct BankMetadata {
22
+ pub bank: HashMap<String, String>,
23
+ pub triggers: Option<Vec<HashMap<String, String>>>,
24
+ }
25
+
17
26
  #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
18
27
  pub struct BankEntry {
19
28
  pub path: String,
20
29
  pub version: Option<String>,
21
- pub author: Option<String>,
30
+ }
31
+
32
+ #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
33
+ pub struct PluginEntry {
34
+ pub path: String,
35
+ pub version: String,
36
+ pub author: String,
37
+ pub access: String,
22
38
  }
23
39
 
24
40
  impl Config {
@@ -31,6 +47,7 @@ impl Config {
31
47
  repeat: None,
32
48
  },
33
49
  banks: Some(Vec::new()),
50
+ plugins: Some(Vec::new()),
34
51
  }
35
52
  }
36
53
 
@@ -48,6 +65,7 @@ impl Config {
48
65
  repeat,
49
66
  },
50
67
  banks: Some(Vec::new()),
68
+ plugins: Some(Vec::new()),
51
69
  }
52
70
  }
53
71