@devaloop/devalang 0.0.1-beta.2 → 0.0.1-beta.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.
Files changed (159) hide show
  1. package/Cargo.toml +84 -81
  2. package/README.md +3 -2
  3. package/docs/CHANGELOG.md +41 -0
  4. package/docs/ROADMAP.md +3 -3
  5. package/examples/chain.deva +19 -0
  6. package/examples/plugin.deva +10 -10
  7. package/examples/routing.deva +23 -0
  8. package/out-tsc/bin/project-version.json +6 -0
  9. package/out-tsc/pkg/devalang_core_bg.wasm.d.ts +8 -8
  10. package/out-tsc/scripts/version/copy-to-binary.d.ts +1 -0
  11. package/out-tsc/scripts/version/copy-to-binary.js +79 -0
  12. package/package.json +23 -10
  13. package/project-version.json +3 -3
  14. package/rust/bindings/Cargo.toml +9 -0
  15. package/rust/bindings/src/lib.rs +86 -0
  16. package/rust/cli/addon/commands.rs +35 -0
  17. package/rust/cli/addon/download.rs +234 -0
  18. package/rust/cli/addon/install.rs +33 -0
  19. package/rust/cli/addon/list.rs +224 -0
  20. package/rust/cli/addon/metadata.rs +124 -0
  21. package/rust/cli/addon/mod.rs +8 -0
  22. package/rust/cli/addon/remove.rs +271 -0
  23. package/rust/cli/addon/update.rs +305 -0
  24. package/rust/cli/{install/addon.rs → addon/utils.rs} +109 -118
  25. package/rust/cli/build/commands.rs +153 -153
  26. package/rust/cli/build/process.rs +165 -165
  27. package/rust/cli/check/mod.rs +208 -208
  28. package/rust/cli/discover/commands.rs +275 -253
  29. package/rust/cli/discover/config.rs +109 -111
  30. package/rust/cli/discover/fs.rs +19 -19
  31. package/rust/cli/discover/install.rs +214 -103
  32. package/rust/cli/discover/metadata.rs +48 -48
  33. package/rust/cli/discover/mod.rs +5 -5
  34. package/rust/cli/me/commands.rs +52 -0
  35. package/rust/cli/me/mod.rs +1 -0
  36. package/rust/cli/mod.rs +12 -12
  37. package/rust/cli/parser.rs +30 -69
  38. package/rust/cli/play/commands.rs +375 -375
  39. package/rust/cli/play/process.rs +159 -159
  40. package/rust/core/audio/engine/driver.rs +19 -2
  41. package/rust/core/audio/engine/export.rs +169 -169
  42. package/rust/core/audio/engine/mod.rs +56 -56
  43. package/rust/core/audio/engine/notes/dsp.rs +88 -85
  44. package/rust/core/audio/engine/notes/mod.rs +53 -44
  45. package/rust/core/audio/engine/notes/params.rs +294 -294
  46. package/rust/core/audio/engine/sample/insert.rs +148 -47
  47. package/rust/core/audio/engine/sample/mod.rs +40 -40
  48. package/rust/core/audio/engine/sample/padding.rs +170 -170
  49. package/rust/core/audio/evaluator/condition.rs +61 -61
  50. package/rust/core/audio/evaluator/numeric.rs +152 -152
  51. package/rust/core/audio/evaluator/rhs.rs +16 -16
  52. package/rust/core/audio/evaluator/string_expr.rs +94 -94
  53. package/rust/core/audio/interpreter/driver.rs +574 -574
  54. package/rust/core/audio/interpreter/mod.rs +2 -2
  55. package/rust/core/audio/interpreter/statements/arrow_call/interprete.rs +9 -5
  56. package/rust/core/audio/interpreter/statements/arrow_call/methods/chord.rs +398 -384
  57. package/rust/core/audio/interpreter/statements/arrow_call/methods/effects.rs +323 -0
  58. package/rust/core/audio/interpreter/statements/arrow_call/methods/mod.rs +1 -0
  59. package/rust/core/audio/interpreter/statements/arrow_call/methods/note.rs +66 -11
  60. package/rust/core/audio/interpreter/statements/arrow_call/mod.rs +3 -3
  61. package/rust/core/audio/interpreter/statements/arrow_call/types/arp.rs +192 -192
  62. package/rust/core/audio/interpreter/statements/arrow_call/types/mod.rs +24 -24
  63. package/rust/core/audio/interpreter/statements/arrow_call/types/pad.rs +116 -116
  64. package/rust/core/audio/interpreter/statements/arrow_call/types/pluck.rs +97 -97
  65. package/rust/core/audio/interpreter/statements/arrow_call/types/sub.rs +100 -100
  66. package/rust/core/audio/interpreter/statements/automate.rs +16 -16
  67. package/rust/core/audio/interpreter/statements/call.rs +31 -1
  68. package/rust/core/audio/interpreter/statements/condition.rs +72 -72
  69. package/rust/core/audio/interpreter/statements/function.rs +24 -24
  70. package/rust/core/audio/interpreter/statements/let_.rs +36 -36
  71. package/rust/core/audio/interpreter/statements/load.rs +17 -17
  72. package/rust/core/audio/interpreter/statements/loop_.rs +115 -115
  73. package/rust/core/audio/interpreter/statements/spawn.rs +51 -2
  74. package/rust/core/audio/interpreter/statements/trigger.rs +242 -239
  75. package/rust/core/audio/loader/trigger.rs +98 -98
  76. package/rust/core/audio/player.rs +70 -70
  77. package/rust/core/audio/special/mod.rs +9 -9
  78. package/rust/core/builder/mod.rs +129 -129
  79. package/rust/core/debugger/lexer.rs +27 -27
  80. package/rust/core/debugger/logs.rs +52 -52
  81. package/rust/core/debugger/preprocessor.rs +27 -27
  82. package/rust/core/debugger/store.rs +38 -38
  83. package/rust/core/lexer/driver.rs +59 -59
  84. package/rust/core/lexer/handler/arrow.rs +82 -82
  85. package/rust/core/lexer/handler/at.rs +21 -21
  86. package/rust/core/lexer/handler/brace.rs +41 -41
  87. package/rust/core/lexer/handler/colon.rs +21 -21
  88. package/rust/core/lexer/handler/comment.rs +30 -30
  89. package/rust/core/lexer/handler/dot.rs +21 -21
  90. package/rust/core/lexer/handler/driver.rs +337 -337
  91. package/rust/core/lexer/handler/identifier.rs +47 -47
  92. package/rust/core/lexer/handler/indent.rs +66 -66
  93. package/rust/core/lexer/handler/mod.rs +15 -15
  94. package/rust/core/lexer/handler/newline.rs +23 -23
  95. package/rust/core/lexer/handler/number.rs +31 -31
  96. package/rust/core/lexer/handler/operator.rs +46 -46
  97. package/rust/core/lexer/handler/parenthesis.rs +41 -41
  98. package/rust/core/lexer/handler/slash.rs +21 -21
  99. package/rust/core/lexer/handler/string.rs +63 -63
  100. package/rust/core/lexer/mod.rs +3 -3
  101. package/rust/core/mod.rs +9 -9
  102. package/rust/core/parser/driver/block.rs +111 -111
  103. package/rust/core/parser/driver/cursor.rs +82 -82
  104. package/rust/core/parser/driver/driver_impl.rs +21 -1
  105. package/rust/core/parser/driver/mod.rs +6 -6
  106. package/rust/core/parser/driver/parse_array.rs +120 -120
  107. package/rust/core/parser/driver/parse_map.rs +247 -223
  108. package/rust/core/parser/driver/parser.rs +160 -160
  109. package/rust/core/parser/handler/arrow_call.rs +65 -14
  110. package/rust/core/parser/handler/identifier/synth.rs +171 -135
  111. package/rust/core/parser/handler/mod.rs +9 -9
  112. package/rust/core/parser/handler/pattern.rs +24 -1
  113. package/rust/core/plugin/loader.rs +137 -137
  114. package/rust/core/plugin/mod.rs +2 -2
  115. package/rust/core/plugin/runner/non_wasm.rs +481 -297
  116. package/rust/core/plugin/runner/wasm32.rs +1 -0
  117. package/rust/core/preprocessor/loader/inject.rs +313 -278
  118. package/rust/core/preprocessor/loader/loader_helpers.rs +110 -110
  119. package/rust/core/preprocessor/loader/mod.rs +235 -235
  120. package/rust/core/preprocessor/module.rs +55 -55
  121. package/rust/core/preprocessor/processor/handlers.rs +107 -107
  122. package/rust/core/preprocessor/resolver/bank.rs +49 -49
  123. package/rust/core/preprocessor/resolver/call.rs +124 -124
  124. package/rust/core/preprocessor/resolver/condition.rs +95 -95
  125. package/rust/core/preprocessor/resolver/driver.rs +324 -324
  126. package/rust/core/preprocessor/resolver/function.rs +69 -69
  127. package/rust/core/preprocessor/resolver/group.rs +122 -122
  128. package/rust/core/preprocessor/resolver/let_.rs +32 -32
  129. package/rust/core/preprocessor/resolver/loop_.rs +318 -318
  130. package/rust/core/preprocessor/resolver/mod.rs +16 -16
  131. package/rust/core/preprocessor/resolver/pattern.rs +95 -83
  132. package/rust/core/preprocessor/resolver/spawn.rs +99 -99
  133. package/rust/core/preprocessor/resolver/synth.rs +54 -54
  134. package/rust/core/preprocessor/resolver/tempo.rs +48 -48
  135. package/rust/core/preprocessor/resolver/trigger.rs +116 -116
  136. package/rust/core/preprocessor/resolver/value.rs +176 -176
  137. package/rust/core/store/global.rs +57 -57
  138. package/rust/lib.rs +323 -323
  139. package/rust/macros/Cargo.toml +14 -0
  140. package/rust/macros/src/lib.rs +52 -0
  141. package/rust/main.rs +311 -142
  142. package/rust/types/Cargo.toml +1 -1
  143. package/rust/types/src/addons.rs +3 -1
  144. package/rust/types/src/config.rs +1 -3
  145. package/rust/utils/Cargo.toml +5 -2
  146. package/rust/utils/src/file.rs +397 -14
  147. package/rust/utils/src/path.rs +31 -2
  148. package/rust/utils/src/version.rs +38 -7
  149. package/rust/web/auth.rs +5 -0
  150. package/rust/web/forge.rs +5 -0
  151. package/rust/web/mod.rs +5 -3
  152. package/typescript/scripts/version/copy-to-binary.ts +82 -0
  153. package/rust/cli/bank/api.rs +0 -122
  154. package/rust/cli/bank/commands.rs +0 -306
  155. package/rust/cli/bank/mod.rs +0 -29
  156. package/rust/cli/install/bank.rs +0 -72
  157. package/rust/cli/install/commands.rs +0 -35
  158. package/rust/cli/install/mod.rs +0 -4
  159. package/rust/cli/install/plugin.rs +0 -80
@@ -0,0 +1,82 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+
4
+ const argv = process.argv.slice(2);
5
+ let sourceArg: string | undefined;
6
+ let binaryArg: string | undefined;
7
+ let outDirArg: string | undefined;
8
+
9
+ for (let i = 0; i < argv.length; i++) {
10
+ const a = argv[i];
11
+ if (a === "--source") {
12
+ sourceArg = argv[++i];
13
+ } else if (a === "--binary") {
14
+ binaryArg = argv[++i];
15
+ } else if (a === "--out-dir") {
16
+ outDirArg = argv[++i];
17
+ } else if (a === "--help" || a === "-h") {
18
+ process.exit(0);
19
+ } else {
20
+ console.error(`Unknown arg: ${a}`);
21
+ process.exit(1);
22
+ }
23
+ }
24
+
25
+ // Default source: attempt to locate project-version.json at repo root
26
+ const defaultSource = path.resolve(
27
+ __dirname,
28
+ "..",
29
+ "..",
30
+ "..",
31
+ "project-version.json"
32
+ );
33
+ const sourcePath = sourceArg ? path.resolve(sourceArg) : defaultSource;
34
+
35
+ if (!fs.existsSync(sourcePath)) {
36
+ console.error(
37
+ `Source project-version.json not found at '${sourcePath}'. Please provide --source or ensure file exists.`
38
+ );
39
+ process.exit(2);
40
+ }
41
+
42
+ let destDir: string | null = null;
43
+
44
+ if (binaryArg) {
45
+ const binPath = path.resolve(binaryArg);
46
+ // If it's an existing file, use its directory, otherwise assume user passed target path and use its parent
47
+ if (fs.existsSync(binPath) && fs.statSync(binPath).isFile()) {
48
+ destDir = path.dirname(binPath);
49
+ } else {
50
+ // If binPath looks like a file path (has extension) use parent, else treat as dir
51
+ const ext = path.extname(binPath);
52
+ if (ext) {
53
+ destDir = path.dirname(binPath);
54
+ } else {
55
+ destDir = binPath;
56
+ }
57
+ }
58
+ } else if (outDirArg) {
59
+ destDir = path.resolve(outDirArg);
60
+ } else {
61
+ // Default: try to copy next to the running node current working dir (useful when packaging)
62
+ destDir = process.cwd();
63
+ }
64
+
65
+ if (!destDir) {
66
+ console.error("Could not resolve destination directory");
67
+ process.exit(3);
68
+ }
69
+
70
+ try {
71
+ if (!fs.existsSync(destDir)) {
72
+ fs.mkdirSync(destDir, { recursive: true });
73
+ }
74
+
75
+ const destPath = path.join(destDir, "project-version.json");
76
+ fs.copyFileSync(sourcePath, destPath);
77
+ console.log(`project-version.json copied to '${destPath}'`);
78
+ process.exit(0);
79
+ } catch (err) {
80
+ console.error("Failed to copy project-version.json:", err);
81
+ process.exit(4);
82
+ }
@@ -1,122 +0,0 @@
1
- use crate::web::cdn::get_cdn_url;
2
- use devalang_types::{BankFile, BankInfo};
3
- use serde::Deserialize;
4
-
5
- #[derive(Debug, Deserialize)]
6
- pub struct BankList {
7
- pub bank: Vec<BankInfo>,
8
- }
9
-
10
- #[derive(Debug, Deserialize)]
11
- pub struct BankVersion {
12
- pub version: String,
13
- }
14
-
15
- pub async fn handle_bank_info_command(
16
- name: String,
17
- ) -> Result<BankInfo, Box<dyn std::error::Error>> {
18
- let cdn_url = get_cdn_url();
19
- let url = format!("{}/bank/{}/info", cdn_url, name);
20
-
21
- let response = reqwest::get(&url).await?;
22
-
23
- if !response.status().is_success() {
24
- return Err(format!("Failed to fetch bank info: HTTP {}", response.status()).into());
25
- }
26
-
27
- let bytes = response.bytes().await?;
28
-
29
- let parsed: BankInfo = serde_json::from_slice(&bytes)?;
30
-
31
- println!("📦 Bank Info for '{}':", name);
32
- println!(" - Name: {}", parsed.name);
33
- println!(" - Version: {}", parsed.version);
34
- println!(" - Description: {}", parsed.description);
35
- println!(" - Author: {}", parsed.author);
36
-
37
- Ok(parsed)
38
- }
39
-
40
- pub async fn fetch_latest_version(
41
- bank_name: String,
42
- ) -> Result<BankVersion, Box<dyn std::error::Error>> {
43
- let cdn_url = get_cdn_url();
44
- let url = format!("{}/bank/{}/version", cdn_url, bank_name);
45
-
46
- let response = reqwest::get(url).await?;
47
-
48
- if !response.status().is_success() {
49
- return Err(format!("❌ Failed to fetch version: HTTP {}", response.status()).into());
50
- }
51
-
52
- let bytes = response.bytes().await?;
53
-
54
- let version: BankVersion = serde_json::from_slice(&bytes)?;
55
-
56
- Ok(version)
57
- }
58
-
59
- pub async fn list_external_banks() -> Result<Vec<BankInfo>, Box<dyn std::error::Error>> {
60
- let cdn_url = get_cdn_url();
61
- let url = format!("{}/bank/list", cdn_url);
62
-
63
- let response = reqwest::get(url).await?;
64
-
65
- if !response.status().is_success() {
66
- return Err(format!("❌ Failed to fetch bank list: HTTP {}", response.status()).into());
67
- }
68
-
69
- let bytes = response.bytes().await?;
70
-
71
- let parsed: BankList = serde_json::from_slice(&bytes)?;
72
-
73
- Ok(parsed.bank)
74
- }
75
-
76
- pub async fn list_installed_banks() -> Result<Vec<BankFile>, String> {
77
- let deva_dir = devalang_utils::path::ensure_deva_dir()?;
78
- let bank_dir = deva_dir.join("banks");
79
-
80
- let mut banks = Vec::new();
81
-
82
- if !bank_dir.exists() {
83
- return Ok(banks); // No banks installed
84
- }
85
-
86
- let config_path = devalang_utils::path::get_devalang_config_path()?;
87
- let config = crate::config::ops::load_config(Some(&config_path))
88
- .ok_or_else(|| format!("Failed to load config from '{}'", config_path.display()))?;
89
-
90
- let config_banks = config.banks.clone();
91
-
92
- if let Some(banks_in_toml) = config_banks {
93
- for bank in banks_in_toml {
94
- let bank_name = bank
95
- .path
96
- .strip_prefix("devalang://bank/")
97
- .unwrap_or(&bank.path)
98
- .to_string();
99
-
100
- let bank_path = bank_dir.join(&bank_name);
101
- if bank_path.exists() {
102
- let bank_info_path = bank_path.join("bank.toml");
103
-
104
- if bank_info_path.exists() {
105
- let content = std::fs::read_to_string(&bank_info_path)
106
- .map_err(|e| format!("Failed to read bank info: {}", e))?;
107
-
108
- match toml::from_str::<BankFile>(&content) {
109
- Ok(bank_info) => banks.push(bank_info),
110
- Err(_err) => {
111
- eprintln!("❌ Error parsing bank info for '{}'", bank_name);
112
- }
113
- }
114
- } else {
115
- eprintln!("❌ Bank info file not found for '{}'", bank_name);
116
- }
117
- }
118
- }
119
- }
120
-
121
- Ok(banks)
122
- }
@@ -1,306 +0,0 @@
1
- use crate::cli::install::bank::install_bank;
2
- use crate::config::ops::load_config;
3
- use devalang_core::config::driver::ProjectConfigExt;
4
- use devalang_types::{BankFile, BankInfo};
5
- use devalang_utils::path as path_utils;
6
- use std::fs;
7
-
8
- pub async fn handle_update_bank_command(name: Option<String>) -> Result<(), String> {
9
- let deva_dir = path_utils::ensure_deva_dir()?;
10
- let bank_dir = deva_dir.join("banks");
11
-
12
- if !bank_dir.exists() {
13
- fs::create_dir_all(bank_dir.clone())
14
- .map_err(|e| format!("Failed to create bank directory: {}", e))?;
15
- }
16
-
17
- if let Some(name) = name {
18
- let bank_path = bank_dir.join(&name);
19
- if !bank_path.exists() {
20
- return Err(format!("Bank '{}' is not installed", name));
21
- }
22
-
23
- // Update specific bank
24
- let latest_version = match crate::cli::bank::api::fetch_latest_version(name.clone()).await {
25
- Ok(version) => version,
26
- Err(err) => {
27
- eprintln!("❌ Error fetching latest version for '{}': {}", name, err);
28
- return Err(format!("Failed to fetch latest version for '{}'", name));
29
- }
30
- };
31
-
32
- let local_bank_info_path = bank_path.join("bank.toml");
33
- let local_version = match fs::read_to_string(&local_bank_info_path)
34
- .ok()
35
- .and_then(|content| toml::from_str::<BankFile>(&content).ok())
36
- .map(|bf| bf.bank.version)
37
- {
38
- Some(version) => version,
39
- None => {
40
- eprintln!(
41
- "⚠️ Unable to read local version for '{}', forcing reinstall...",
42
- name
43
- );
44
- "".to_string() // Force update
45
- }
46
- };
47
-
48
- if local_version != latest_version.version {
49
- if let Err(e) = update_bank(&name, &latest_version.version).await {
50
- eprintln!("❌ Error updating bank '{}': {}", name, e);
51
- } else {
52
- println!(
53
- "✅ Bank '{}' updated to version '{}'",
54
- name, latest_version.version
55
- );
56
- }
57
- } else {
58
- println!(
59
- "Bank '{}' is already up-to-date (version {})",
60
- name, latest_version.version
61
- );
62
-
63
- // Verify if the bank directory exists
64
- if !bank_path.exists() {
65
- eprintln!(
66
- "❌ Bank directory for '{}' does not exist, reinstalling...",
67
- name
68
- );
69
- if let Err(e) = install_bank(&name, &deva_dir).await {
70
- eprintln!("❌ Error reinstalling bank '{}': {}", name, e);
71
- } else {
72
- println!("✅ Bank '{}' reinstalled successfully!", name);
73
- }
74
- }
75
- }
76
- } else {
77
- // Update all banks
78
- let config_path = path_utils::get_devalang_config_path()?;
79
- let config = load_config(Some(&config_path))
80
- .ok_or_else(|| format!("Failed to load config from '{}'", config_path.display()))?;
81
-
82
- let config_banks = config.banks.clone();
83
-
84
- if let Some(banks) = config_banks {
85
- for bank in banks {
86
- let bank_name = bank
87
- .path
88
- .strip_prefix("devalang://bank/")
89
- .unwrap_or(&bank.path)
90
- .to_string();
91
-
92
- let latest_version =
93
- match crate::cli::bank::api::fetch_latest_version(bank_name.clone()).await {
94
- Ok(version) => version,
95
- Err(err) => {
96
- eprintln!(
97
- "❌ Error fetching latest version for '{}': {}",
98
- bank_name, err
99
- );
100
- continue;
101
- }
102
- };
103
-
104
- if let Some(local_bank_version) = bank.version {
105
- if latest_version.version != local_bank_version {
106
- if let Err(e) = update_bank(&bank_name, &latest_version.version).await {
107
- eprintln!("❌ Error updating bank '{}': {}", bank_name, e);
108
- } else {
109
- println!(
110
- "✅ Bank '{}' updated to version '{}'",
111
- bank_name, latest_version.version
112
- );
113
- }
114
- } else {
115
- println!(
116
- "Bank '{}' is already up-to-date (version {})",
117
- bank_name, local_bank_version
118
- );
119
-
120
- // Verify if the bank directory exists
121
- let bank_path = bank_dir.join(&bank_name);
122
-
123
- if !bank_path.exists() {
124
- eprintln!(
125
- "❌ Bank directory for '{}' does not exist, reinstalling...",
126
- bank_name
127
- );
128
- if let Err(e) = install_bank(&bank_name, &deva_dir).await {
129
- eprintln!("❌ Error reinstalling bank '{}': {}", bank_name, e);
130
- } else {
131
- println!("✅ Bank '{}' reinstalled successfully!", bank_name);
132
- }
133
- }
134
- }
135
- } else {
136
- // If the bank version is not specified in the config, install it
137
- if let Err(e) = install_bank(&bank_name, &deva_dir).await {
138
- eprintln!("❌ Error installing bank '{}': {}", bank_name, e);
139
- } else {
140
- println!("✅ Bank '{}' installed successfully!", bank_name);
141
- }
142
- }
143
- }
144
- }
145
- }
146
-
147
- Ok(())
148
- }
149
-
150
- async fn update_bank(bank_name: &str, _latest_version: &str) -> Result<(), String> {
151
- let deva_dir = path_utils::ensure_deva_dir()?;
152
-
153
- // First, delete the existing bank directory
154
- let bank_dir = deva_dir.join("banks").join(bank_name);
155
-
156
- if bank_dir.exists() {
157
- std::fs::remove_dir_all(&bank_dir).unwrap_or_else(|_| {
158
- eprintln!(
159
- "⚠️ Failed to remove old bank directory for '{}', aborting !",
160
- bank_name
161
- );
162
- std::process::exit(1);
163
- });
164
- }
165
-
166
- // Now, install the new version
167
- if let Err(e) = install_bank(bank_name, &deva_dir).await {
168
- eprintln!("❌ Error installing bank '{}': {}", bank_name, e);
169
- } else {
170
- println!("✅ Bank '{}' installed successfully!", bank_name);
171
- }
172
-
173
- let config_path = path_utils::get_devalang_config_path()?;
174
- let _config = load_config(Some(&config_path))
175
- .ok_or_else(|| format!("Failed to load config from '{}'", config_path.display()))?;
176
-
177
- // Update the bank version in the config
178
- if let Some(mut config) = crate::config::ops::load_config(Some(&config_path)) {
179
- if let Some(banks) = config.banks.as_mut() {
180
- for bank in banks.iter_mut() {
181
- if bank
182
- .path
183
- .strip_prefix("devalang://bank/")
184
- .unwrap_or(&bank.path)
185
- == bank_name
186
- {
187
- bank.version = Some(_latest_version.to_string());
188
- }
189
- }
190
-
191
- if let Err(e) = config.write_config(&config) {
192
- eprintln!("Warning: failed to write updated config: {}", e);
193
- }
194
- }
195
- }
196
-
197
- Ok(())
198
- }
199
-
200
- pub async fn handle_remove_bank_command(name: String) -> Result<(), String> {
201
- let deva_dir = path_utils::ensure_deva_dir()?;
202
- let bank_dir = deva_dir.join("banks");
203
-
204
- let bank_path = bank_dir.join(&name);
205
-
206
- if !bank_path.exists() {
207
- return Err(format!("Bank '{}' is not installed", name));
208
- }
209
-
210
- std::fs::remove_dir_all(&bank_path).map_err(|e| format!("Failed to remove bank: {}", e))?;
211
-
212
- // Remove the bank from the config
213
- let config_path = path_utils::get_devalang_config_path()?;
214
- let _config = load_config(Some(&config_path))
215
- .ok_or_else(|| format!("Failed to load config from '{}'", config_path.display()))?;
216
-
217
- // Remove the bank from the config
218
- if let Some(mut config) = crate::config::ops::load_config(Some(&config_path)) {
219
- if let Some(banks) = config.banks.as_mut() {
220
- banks.retain(|b| {
221
- let name_in_path = b.path.strip_prefix("devalang://bank/").unwrap_or(&b.path);
222
- name_in_path != name
223
- });
224
-
225
- if let Err(e) = config.write_config(&config) {
226
- eprintln!("Warning: failed to write updated config: {}", e);
227
- }
228
- }
229
- }
230
-
231
- println!("✅ Bank '{}' removed successfully", name);
232
-
233
- Ok(())
234
- }
235
-
236
- pub async fn handle_bank_available_command() -> Result<(), String> {
237
- let bank_list = match crate::cli::bank::api::list_external_banks().await {
238
- Ok(list) => list,
239
- Err(_err) => {
240
- eprintln!("❌ Error fetching bank list");
241
- return Err("Failed to fetch bank list".into());
242
- }
243
- };
244
-
245
- println!("Available banks for current project :");
246
- println!(" ");
247
-
248
- for bank in bank_list {
249
- println!("📦 {}", bank.name);
250
- println!(" - Version: {}", bank.version);
251
- println!(" - Description: {}", bank.description);
252
- println!(" - Author: {}", bank.author);
253
- println!(" ");
254
- }
255
-
256
- Ok(())
257
- }
258
-
259
- pub async fn handle_bank_info_command(
260
- name: String,
261
- ) -> Result<BankInfo, Box<dyn std::error::Error>> {
262
- crate::cli::bank::api::handle_bank_info_command(name).await
263
- }
264
-
265
- pub async fn handle_bank_list_command() -> Result<(), String> {
266
- let bank_list = match crate::cli::bank::api::list_installed_banks().await {
267
- Ok(list) => list,
268
- Err(_err) => {
269
- eprintln!("❌ Error fetching bank list");
270
- return Err("Failed to fetch bank list".into());
271
- }
272
- };
273
-
274
- println!("Installed banks for current project :");
275
-
276
- for bank_toml in bank_list {
277
- let latest_version =
278
- match crate::cli::bank::api::fetch_latest_version(bank_toml.bank.name.clone()).await {
279
- Ok(version) => version,
280
- Err(_err) => {
281
- eprintln!(
282
- "❌ Error fetching latest version for '{}'",
283
- bank_toml.bank.name
284
- );
285
- continue;
286
- }
287
- };
288
-
289
- let is_latest = if latest_version.version == bank_toml.bank.version {
290
- "✅"
291
- } else {
292
- "❗"
293
- };
294
-
295
- println!(" ");
296
- println!("📦 {}", bank_toml.bank.name);
297
- println!(
298
- " - Version: v{} {} (latest: v{})",
299
- bank_toml.bank.version, is_latest, latest_version.version
300
- );
301
- println!(" - Description: {}", bank_toml.bank.description);
302
- println!(" - Author: {}", bank_toml.bank.author);
303
- }
304
-
305
- Ok(())
306
- }
@@ -1,29 +0,0 @@
1
- use devalang_types::BankInfo;
2
- use serde::Deserialize;
3
-
4
- pub mod api;
5
- pub mod commands;
6
-
7
- #[derive(Debug, Deserialize)]
8
- pub struct BankList {
9
- pub bank: Vec<BankInfo>,
10
- }
11
-
12
- #[derive(Debug, Deserialize)]
13
- pub struct BankInfoFetched {
14
- pub name: String,
15
- pub version: String,
16
- pub description: String,
17
- pub author: String,
18
- pub latest_version: String,
19
- }
20
-
21
- #[derive(Debug, Deserialize)]
22
- pub struct BankVersion {
23
- pub version: String,
24
- }
25
-
26
- pub use commands::{
27
- handle_bank_available_command, handle_bank_info_command, handle_bank_list_command,
28
- handle_remove_bank_command, handle_update_bank_command,
29
- };
@@ -1,72 +0,0 @@
1
- use crate::{
2
- cli::install::addon::ask_api_for_signed_url, config::ops::load_config,
3
- web::cdn::download_from_cdn,
4
- };
5
- use devalang_core::config::driver::ProjectConfigExt;
6
- use devalang_types::AddonType;
7
- use devalang_types::ProjectConfigBankEntry;
8
- use devalang_utils::{
9
- logger::{LogLevel, Logger},
10
- path as path_utils,
11
- };
12
- use std::path::Path;
13
-
14
- pub async fn install_bank(name: &str, target_dir: &Path) -> Result<(), String> {
15
- let logger = Logger::new();
16
-
17
- let signed_url = ask_api_for_signed_url(AddonType::Bank, name).await?;
18
-
19
- let bank_dir = target_dir.join("banks");
20
- let archive_path = path_utils::ensure_deva_dir()?
21
- .join("tmp")
22
- .join(format!("{}.devabank", name));
23
- let extract_path = bank_dir.join(name);
24
-
25
- download_from_cdn(&signed_url, &archive_path)
26
- .await
27
- .map_err(|e| format!("Failed to download: {}", e))?;
28
-
29
- if extract_path.exists() {
30
- logger.log_message(
31
- LogLevel::Warning,
32
- &format!(
33
- "Bank '{}' already exists at '{}'. Skipping install.",
34
- name,
35
- extract_path.display()
36
- ),
37
- );
38
-
39
- return Ok(());
40
- }
41
-
42
- // Add the bank to the config
43
- let config_path = path_utils::get_devalang_config_path()?;
44
- let mut config = load_config(Some(&config_path))
45
- .ok_or_else(|| format!("Failed to load config from '{}'", config_path.display()))?;
46
-
47
- let dependency_path = format!("devalang://bank/{}", name);
48
-
49
- devalang_utils::file::extract_zip_safely(&archive_path, &extract_path)
50
- .map_err(|e| format!("Failed to extract: {}", e))?;
51
-
52
- // Add the bank to the config if not already present
53
- if config.banks.is_none() {
54
- config.banks = Some(Vec::new());
55
- }
56
-
57
- if let Some(banks) = config.banks.as_mut() {
58
- let exists = banks.iter().any(|b| b.path == dependency_path);
59
- if !exists {
60
- banks.push(ProjectConfigBankEntry {
61
- path: dependency_path.clone(),
62
- version: None,
63
- });
64
-
65
- if let Err(e) = config.write_config(&config) {
66
- eprintln!("Warning: failed to write config: {}", e);
67
- }
68
- }
69
- }
70
-
71
- Ok(())
72
- }
@@ -1,35 +0,0 @@
1
- use crate::cli::install::addon::install_addon;
2
- #[cfg(feature = "cli")]
3
- use devalang_types::AddonType;
4
- use devalang_utils::path as path_utils;
5
-
6
- /// Handles the installation command for a given addon type and name.
7
- #[cfg(feature = "cli")]
8
- pub async fn handle_install_command(name: String, addon_type: AddonType) -> Result<(), String> {
9
- use devalang_utils::{
10
- logger::{LogLevel, Logger},
11
- spinner::start_spinner,
12
- };
13
-
14
- let logger = Logger::new();
15
- let deva_dir = path_utils::ensure_deva_dir()?;
16
-
17
- let spinner = start_spinner("Installing...");
18
-
19
- if let Err(e) = install_addon(addon_type.clone(), name.as_str(), &deva_dir).await {
20
- spinner.finish_and_clear();
21
- logger.log_message_with_trace(
22
- LogLevel::Error,
23
- &format!("Error installing {:?} '{}'", addon_type, name),
24
- vec![&e],
25
- );
26
- } else {
27
- spinner.finish_and_clear();
28
- logger.log_message(
29
- LogLevel::Success,
30
- &format!("{:?} '{}' installed successfully!", addon_type, name),
31
- );
32
- }
33
-
34
- Ok(())
35
- }
@@ -1,4 +0,0 @@
1
- pub mod addon;
2
- pub mod bank;
3
- pub mod commands;
4
- pub mod plugin;