@devaloop/devalang 0.0.1-beta.3 → 0.1.1

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 (345) hide show
  1. package/README.md +182 -152
  2. package/out-tsc/api.d.ts +180 -0
  3. package/out-tsc/api.d.ts.map +1 -0
  4. package/out-tsc/api.js +286 -0
  5. package/out-tsc/api.js.map +1 -0
  6. package/out-tsc/bin/index.d.ts +12 -0
  7. package/out-tsc/bin/index.d.ts.map +1 -0
  8. package/out-tsc/bin/index.js +20 -54
  9. package/out-tsc/bin/index.js.map +1 -0
  10. package/out-tsc/examples/basic-usage.d.ts +8 -0
  11. package/out-tsc/examples/basic-usage.d.ts.map +1 -0
  12. package/out-tsc/examples/basic-usage.js +113 -0
  13. package/out-tsc/examples/basic-usage.js.map +1 -0
  14. package/out-tsc/index.d.ts +19 -5
  15. package/out-tsc/index.d.ts.map +1 -0
  16. package/out-tsc/index.js +24 -6
  17. package/out-tsc/index.js.map +1 -0
  18. package/out-tsc/scripts/copy-wasm-dts.d.ts +7 -0
  19. package/out-tsc/scripts/copy-wasm-dts.d.ts.map +1 -0
  20. package/out-tsc/scripts/copy-wasm-dts.js +36 -32
  21. package/out-tsc/scripts/copy-wasm-dts.js.map +1 -0
  22. package/out-tsc/scripts/postinstall.d.ts +1 -0
  23. package/out-tsc/scripts/postinstall.d.ts.map +1 -0
  24. package/out-tsc/scripts/postinstall.js +4 -1
  25. package/out-tsc/scripts/postinstall.js.map +1 -0
  26. package/out-tsc/scripts/version/bump.d.ts +5 -1
  27. package/out-tsc/scripts/version/bump.d.ts.map +1 -0
  28. package/out-tsc/scripts/version/bump.js +114 -44
  29. package/out-tsc/scripts/version/bump.js.map +1 -0
  30. package/out-tsc/scripts/version/fetch.d.ts +12 -1
  31. package/out-tsc/scripts/version/fetch.d.ts.map +1 -0
  32. package/out-tsc/scripts/version/fetch.js +68 -24
  33. package/out-tsc/scripts/version/fetch.js.map +1 -0
  34. package/out-tsc/scripts/version/index.d.ts +6 -0
  35. package/out-tsc/scripts/version/index.d.ts.map +1 -0
  36. package/out-tsc/scripts/version/index.js +44 -22
  37. package/out-tsc/scripts/version/index.js.map +1 -0
  38. package/out-tsc/scripts/version/sync.d.ts +5 -1
  39. package/out-tsc/scripts/version/sync.d.ts.map +1 -0
  40. package/out-tsc/scripts/version/sync.js +78 -29
  41. package/out-tsc/scripts/version/sync.js.map +1 -0
  42. package/out-tsc/types.d.ts +68 -0
  43. package/out-tsc/types.d.ts.map +1 -0
  44. package/out-tsc/{core/types/value.js → types.js} +4 -0
  45. package/out-tsc/types.js.map +1 -0
  46. package/out-tsc/wasm.d.ts +8 -0
  47. package/out-tsc/wasm.d.ts.map +1 -0
  48. package/out-tsc/{core/index.js → wasm.js} +9 -6
  49. package/out-tsc/wasm.js.map +1 -0
  50. package/package.json +42 -42
  51. package/.cargo/config.toml +0 -2
  52. package/.devalang +0 -9
  53. package/.github/workflows/ci.yml +0 -103
  54. package/Cargo.toml +0 -84
  55. package/docs/CHANGELOG.md +0 -622
  56. package/docs/CONTRIBUTING.md +0 -101
  57. package/docs/ROADMAP.md +0 -38
  58. package/docs/TODO.md +0 -71
  59. package/examples/automation.deva +0 -42
  60. package/examples/bank.deva +0 -7
  61. package/examples/bus.deva +0 -10
  62. package/examples/chain.deva +0 -19
  63. package/examples/condition.deva +0 -20
  64. package/examples/duration.deva +0 -9
  65. package/examples/effect.deva +0 -2
  66. package/examples/events.deva +0 -12
  67. package/examples/filter.deva +0 -11
  68. package/examples/function.deva +0 -15
  69. package/examples/group.deva +0 -12
  70. package/examples/index.deva +0 -63
  71. package/examples/lfo.deva +0 -9
  72. package/examples/loop.deva +0 -10
  73. package/examples/pattern.deva +0 -8
  74. package/examples/plugin.deva +0 -16
  75. package/examples/routing.deva +0 -23
  76. package/examples/samples/hat-808.wav +0 -0
  77. package/examples/samples/kick-808.wav +0 -0
  78. package/examples/synth.deva +0 -24
  79. package/examples/synth_types.deva +0 -17
  80. package/examples/variables.deva +0 -9
  81. package/out-tsc/bin/project-version.json +0 -6
  82. package/out-tsc/core/functions/index.d.ts +0 -42
  83. package/out-tsc/core/functions/index.js +0 -87
  84. package/out-tsc/core/index.d.ts +0 -6
  85. package/out-tsc/core/types/index.d.ts +0 -4
  86. package/out-tsc/core/types/index.js +0 -20
  87. package/out-tsc/core/types/plugin.d.ts +0 -18
  88. package/out-tsc/core/types/plugin.js +0 -2
  89. package/out-tsc/core/types/result.d.ts +0 -27
  90. package/out-tsc/core/types/result.js +0 -2
  91. package/out-tsc/core/types/statement.d.ts +0 -106
  92. package/out-tsc/core/types/statement.js +0 -2
  93. package/out-tsc/core/types/value.d.ts +0 -43
  94. package/out-tsc/pkg/devalang_core.d.ts +0 -15
  95. package/out-tsc/pkg/devalang_core.js +0 -65
  96. package/out-tsc/pkg/devalang_core_bg.wasm.d.ts +0 -34
  97. package/out-tsc/scripts/version/copy-to-binary.d.ts +0 -1
  98. package/out-tsc/scripts/version/copy-to-binary.js +0 -79
  99. package/project-version.json +0 -6
  100. package/rust/bindings/Cargo.toml +0 -9
  101. package/rust/bindings/src/lib.rs +0 -86
  102. package/rust/cli/addon/commands.rs +0 -35
  103. package/rust/cli/addon/download.rs +0 -234
  104. package/rust/cli/addon/install.rs +0 -33
  105. package/rust/cli/addon/list.rs +0 -224
  106. package/rust/cli/addon/metadata.rs +0 -124
  107. package/rust/cli/addon/mod.rs +0 -8
  108. package/rust/cli/addon/remove.rs +0 -271
  109. package/rust/cli/addon/update.rs +0 -305
  110. package/rust/cli/addon/utils.rs +0 -109
  111. package/rust/cli/build/commands.rs +0 -153
  112. package/rust/cli/build/mod.rs +0 -2
  113. package/rust/cli/build/process.rs +0 -165
  114. package/rust/cli/check/mod.rs +0 -208
  115. package/rust/cli/discover/commands.rs +0 -275
  116. package/rust/cli/discover/config.rs +0 -109
  117. package/rust/cli/discover/fs.rs +0 -19
  118. package/rust/cli/discover/install.rs +0 -214
  119. package/rust/cli/discover/metadata.rs +0 -48
  120. package/rust/cli/discover/mod.rs +0 -5
  121. package/rust/cli/init/commands.rs +0 -88
  122. package/rust/cli/init/mod.rs +0 -1
  123. package/rust/cli/login/commands.rs +0 -124
  124. package/rust/cli/login/mod.rs +0 -1
  125. package/rust/cli/me/commands.rs +0 -52
  126. package/rust/cli/me/mod.rs +0 -1
  127. package/rust/cli/mod.rs +0 -12
  128. package/rust/cli/parser.rs +0 -320
  129. package/rust/cli/play/commands.rs +0 -375
  130. package/rust/cli/play/io.rs +0 -17
  131. package/rust/cli/play/mod.rs +0 -5
  132. package/rust/cli/play/process.rs +0 -159
  133. package/rust/cli/play/realtime.rs +0 -91
  134. package/rust/cli/play/utils.rs +0 -23
  135. package/rust/cli/telemetry/commands.rs +0 -22
  136. package/rust/cli/telemetry/event_creator.rs +0 -80
  137. package/rust/cli/telemetry/mod.rs +0 -3
  138. package/rust/cli/telemetry/send.rs +0 -51
  139. package/rust/cli/template/commands.rs +0 -69
  140. package/rust/cli/template/mod.rs +0 -1
  141. package/rust/cli/update/commands.rs +0 -6
  142. package/rust/cli/update/mod.rs +0 -1
  143. package/rust/config/driver.rs +0 -112
  144. package/rust/config/mod.rs +0 -3
  145. package/rust/config/ops.rs +0 -26
  146. package/rust/config/settings.rs +0 -101
  147. package/rust/core/audio/engine/driver.rs +0 -237
  148. package/rust/core/audio/engine/export.rs +0 -169
  149. package/rust/core/audio/engine/helpers.rs +0 -178
  150. package/rust/core/audio/engine/mod.rs +0 -56
  151. package/rust/core/audio/engine/notes/dsp.rs +0 -88
  152. package/rust/core/audio/engine/notes/mod.rs +0 -53
  153. package/rust/core/audio/engine/notes/params.rs +0 -294
  154. package/rust/core/audio/engine/sample/insert.rs +0 -300
  155. package/rust/core/audio/engine/sample/mod.rs +0 -40
  156. package/rust/core/audio/engine/sample/padding.rs +0 -170
  157. package/rust/core/audio/evaluator/condition.rs +0 -61
  158. package/rust/core/audio/evaluator/mod.rs +0 -9
  159. package/rust/core/audio/evaluator/numeric.rs +0 -152
  160. package/rust/core/audio/evaluator/rhs.rs +0 -16
  161. package/rust/core/audio/evaluator/string_expr.rs +0 -94
  162. package/rust/core/audio/interpreter/driver.rs +0 -574
  163. package/rust/core/audio/interpreter/mod.rs +0 -2
  164. package/rust/core/audio/interpreter/statements/arrow_call/interprete.rs +0 -179
  165. package/rust/core/audio/interpreter/statements/arrow_call/methods/chord.rs +0 -398
  166. package/rust/core/audio/interpreter/statements/arrow_call/methods/effects.rs +0 -323
  167. package/rust/core/audio/interpreter/statements/arrow_call/methods/mod.rs +0 -3
  168. package/rust/core/audio/interpreter/statements/arrow_call/methods/note.rs +0 -371
  169. package/rust/core/audio/interpreter/statements/arrow_call/mod.rs +0 -3
  170. package/rust/core/audio/interpreter/statements/arrow_call/types/arp.rs +0 -192
  171. package/rust/core/audio/interpreter/statements/arrow_call/types/mod.rs +0 -24
  172. package/rust/core/audio/interpreter/statements/arrow_call/types/pad.rs +0 -116
  173. package/rust/core/audio/interpreter/statements/arrow_call/types/pluck.rs +0 -97
  174. package/rust/core/audio/interpreter/statements/arrow_call/types/sub.rs +0 -100
  175. package/rust/core/audio/interpreter/statements/automate.rs +0 -16
  176. package/rust/core/audio/interpreter/statements/call.rs +0 -325
  177. package/rust/core/audio/interpreter/statements/condition.rs +0 -72
  178. package/rust/core/audio/interpreter/statements/function.rs +0 -24
  179. package/rust/core/audio/interpreter/statements/let_.rs +0 -36
  180. package/rust/core/audio/interpreter/statements/load.rs +0 -17
  181. package/rust/core/audio/interpreter/statements/loop_.rs +0 -115
  182. package/rust/core/audio/interpreter/statements/mod.rs +0 -12
  183. package/rust/core/audio/interpreter/statements/sleep.rs +0 -28
  184. package/rust/core/audio/interpreter/statements/spawn.rs +0 -302
  185. package/rust/core/audio/interpreter/statements/tempo.rs +0 -40
  186. package/rust/core/audio/interpreter/statements/trigger.rs +0 -242
  187. package/rust/core/audio/loader/mod.rs +0 -1
  188. package/rust/core/audio/loader/trigger.rs +0 -98
  189. package/rust/core/audio/mod.rs +0 -6
  190. package/rust/core/audio/player.rs +0 -70
  191. package/rust/core/audio/special/easing.rs +0 -189
  192. package/rust/core/audio/special/env.rs +0 -45
  193. package/rust/core/audio/special/math.rs +0 -134
  194. package/rust/core/audio/special/mod.rs +0 -9
  195. package/rust/core/audio/special/modulator.rs +0 -143
  196. package/rust/core/builder/mod.rs +0 -129
  197. package/rust/core/debugger/lexer.rs +0 -27
  198. package/rust/core/debugger/logs.rs +0 -52
  199. package/rust/core/debugger/mod.rs +0 -30
  200. package/rust/core/debugger/preprocessor.rs +0 -27
  201. package/rust/core/debugger/store.rs +0 -38
  202. package/rust/core/error/mod.rs +0 -269
  203. package/rust/core/lexer/driver.rs +0 -59
  204. package/rust/core/lexer/handler/arrow.rs +0 -82
  205. package/rust/core/lexer/handler/at.rs +0 -21
  206. package/rust/core/lexer/handler/brace.rs +0 -41
  207. package/rust/core/lexer/handler/colon.rs +0 -21
  208. package/rust/core/lexer/handler/comment.rs +0 -30
  209. package/rust/core/lexer/handler/dot.rs +0 -21
  210. package/rust/core/lexer/handler/driver.rs +0 -337
  211. package/rust/core/lexer/handler/identifier.rs +0 -47
  212. package/rust/core/lexer/handler/indent.rs +0 -66
  213. package/rust/core/lexer/handler/mod.rs +0 -15
  214. package/rust/core/lexer/handler/newline.rs +0 -23
  215. package/rust/core/lexer/handler/number.rs +0 -31
  216. package/rust/core/lexer/handler/operator.rs +0 -46
  217. package/rust/core/lexer/handler/parenthesis.rs +0 -41
  218. package/rust/core/lexer/handler/slash.rs +0 -21
  219. package/rust/core/lexer/handler/string.rs +0 -63
  220. package/rust/core/lexer/mod.rs +0 -3
  221. package/rust/core/lexer/token.rs +0 -91
  222. package/rust/core/mod.rs +0 -9
  223. package/rust/core/parser/driver/block.rs +0 -111
  224. package/rust/core/parser/driver/cursor.rs +0 -82
  225. package/rust/core/parser/driver/driver_impl.rs +0 -159
  226. package/rust/core/parser/driver/mod.rs +0 -6
  227. package/rust/core/parser/driver/parse_array.rs +0 -120
  228. package/rust/core/parser/driver/parse_map.rs +0 -247
  229. package/rust/core/parser/driver/parser.rs +0 -160
  230. package/rust/core/parser/handler/arrow_call.rs +0 -328
  231. package/rust/core/parser/handler/at.rs +0 -279
  232. package/rust/core/parser/handler/bank.rs +0 -104
  233. package/rust/core/parser/handler/condition.rs +0 -83
  234. package/rust/core/parser/handler/dot.rs +0 -148
  235. package/rust/core/parser/handler/identifier/automate.rs +0 -254
  236. package/rust/core/parser/handler/identifier/call.rs +0 -91
  237. package/rust/core/parser/handler/identifier/emit.rs +0 -70
  238. package/rust/core/parser/handler/identifier/function.rs +0 -113
  239. package/rust/core/parser/handler/identifier/group.rs +0 -89
  240. package/rust/core/parser/handler/identifier/let_.rs +0 -173
  241. package/rust/core/parser/handler/identifier/mod.rs +0 -55
  242. package/rust/core/parser/handler/identifier/on.rs +0 -107
  243. package/rust/core/parser/handler/identifier/print.rs +0 -49
  244. package/rust/core/parser/handler/identifier/sleep.rs +0 -96
  245. package/rust/core/parser/handler/identifier/spawn.rs +0 -91
  246. package/rust/core/parser/handler/identifier/synth.rs +0 -171
  247. package/rust/core/parser/handler/loop_.rs +0 -194
  248. package/rust/core/parser/handler/mod.rs +0 -9
  249. package/rust/core/parser/handler/pattern.rs +0 -97
  250. package/rust/core/parser/handler/tempo.rs +0 -105
  251. package/rust/core/parser/mod.rs +0 -3
  252. package/rust/core/parser/statement.rs +0 -10
  253. package/rust/core/plugin/loader.rs +0 -137
  254. package/rust/core/plugin/mod.rs +0 -2
  255. package/rust/core/plugin/runner/mod.rs +0 -11
  256. package/rust/core/plugin/runner/non_wasm.rs +0 -481
  257. package/rust/core/plugin/runner/wasm32.rs +0 -44
  258. package/rust/core/preprocessor/loader/inject.rs +0 -313
  259. package/rust/core/preprocessor/loader/loader_helpers.rs +0 -110
  260. package/rust/core/preprocessor/loader/mod.rs +0 -235
  261. package/rust/core/preprocessor/mod.rs +0 -4
  262. package/rust/core/preprocessor/module.rs +0 -55
  263. package/rust/core/preprocessor/processor/handlers.rs +0 -107
  264. package/rust/core/preprocessor/processor/mod.rs +0 -1
  265. package/rust/core/preprocessor/resolver/bank.rs +0 -49
  266. package/rust/core/preprocessor/resolver/call.rs +0 -124
  267. package/rust/core/preprocessor/resolver/condition.rs +0 -95
  268. package/rust/core/preprocessor/resolver/driver.rs +0 -324
  269. package/rust/core/preprocessor/resolver/function.rs +0 -69
  270. package/rust/core/preprocessor/resolver/group.rs +0 -122
  271. package/rust/core/preprocessor/resolver/let_.rs +0 -32
  272. package/rust/core/preprocessor/resolver/loop_.rs +0 -318
  273. package/rust/core/preprocessor/resolver/mod.rs +0 -16
  274. package/rust/core/preprocessor/resolver/pattern.rs +0 -95
  275. package/rust/core/preprocessor/resolver/spawn.rs +0 -99
  276. package/rust/core/preprocessor/resolver/synth.rs +0 -54
  277. package/rust/core/preprocessor/resolver/tempo.rs +0 -48
  278. package/rust/core/preprocessor/resolver/trigger.rs +0 -116
  279. package/rust/core/preprocessor/resolver/value.rs +0 -176
  280. package/rust/core/store/global.rs +0 -57
  281. package/rust/core/store/mod.rs +0 -1
  282. package/rust/lib.rs +0 -323
  283. package/rust/macros/Cargo.toml +0 -14
  284. package/rust/macros/src/lib.rs +0 -52
  285. package/rust/main.rs +0 -557
  286. package/rust/types/Cargo.toml +0 -11
  287. package/rust/types/src/addons.rs +0 -57
  288. package/rust/types/src/ast.rs +0 -202
  289. package/rust/types/src/config.rs +0 -82
  290. package/rust/types/src/lib.rs +0 -15
  291. package/rust/types/src/plugin.rs +0 -20
  292. package/rust/types/src/store.rs +0 -139
  293. package/rust/types/src/telemetry.rs +0 -85
  294. package/rust/utils/Cargo.toml +0 -29
  295. package/rust/utils/src/error.rs +0 -186
  296. package/rust/utils/src/file.rs +0 -477
  297. package/rust/utils/src/first_usage.rs +0 -97
  298. package/rust/utils/src/lib.rs +0 -9
  299. package/rust/utils/src/logger.rs +0 -200
  300. package/rust/utils/src/path.rs +0 -158
  301. package/rust/utils/src/signature.rs +0 -41
  302. package/rust/utils/src/spinner.rs +0 -20
  303. package/rust/utils/src/version.rs +0 -58
  304. package/rust/utils/src/watcher.rs +0 -46
  305. package/rust/web/api.rs +0 -5
  306. package/rust/web/auth.rs +0 -5
  307. package/rust/web/cdn.rs +0 -34
  308. package/rust/web/forge.rs +0 -5
  309. package/rust/web/mod.rs +0 -5
  310. package/rust/web/sso.rs +0 -5
  311. package/templates/minimal/.devalang +0 -5
  312. package/templates/minimal/README.md +0 -218
  313. package/templates/minimal/src/index.deva +0 -2
  314. package/templates/welcome/.devalang +0 -5
  315. package/templates/welcome/README.md +0 -218
  316. package/templates/welcome/samples/kick-808.wav +0 -0
  317. package/templates/welcome/src/index.deva +0 -61
  318. package/templates/welcome/src/variables.deva +0 -3
  319. package/tests/integration.rs +0 -21
  320. package/tests/rust/cli_check_build.rs +0 -21
  321. package/tests/rust/cli_help.rs +0 -12
  322. package/tests/rust/cli_template_list.rs +0 -10
  323. package/tests/rust/cli_version.rs +0 -11
  324. package/tests/typescript/index.spec.ts +0 -136
  325. package/tests/typescript/playhead.spec.ts +0 -36
  326. package/tests/typescript/render_e2e.spec.ts +0 -77
  327. package/tsconfig.json +0 -115
  328. package/typescript/bin/index.ts +0 -28
  329. package/typescript/core/functions/index.ts +0 -94
  330. package/typescript/core/index.ts +0 -6
  331. package/typescript/core/types/index.ts +0 -4
  332. package/typescript/core/types/plugin.ts +0 -19
  333. package/typescript/core/types/result.ts +0 -29
  334. package/typescript/core/types/statement.ts +0 -47
  335. package/typescript/core/types/value.ts +0 -29
  336. package/typescript/index.ts +0 -8
  337. package/typescript/pkg/devalang_core.d.ts +0 -4
  338. package/typescript/pkg/devalang_core.ts +0 -65
  339. package/typescript/scripts/copy-wasm-dts.ts +0 -41
  340. package/typescript/scripts/postinstall.ts +0 -85
  341. package/typescript/scripts/version/bump.ts +0 -44
  342. package/typescript/scripts/version/copy-to-binary.ts +0 -82
  343. package/typescript/scripts/version/fetch.ts +0 -18
  344. package/typescript/scripts/version/index.ts +0 -25
  345. package/typescript/scripts/version/sync.ts +0 -24
@@ -1,271 +0,0 @@
1
- use crate::config::ops::load_config;
2
- use devalang_core::config::driver::ProjectConfigExt;
3
- use devalang_utils::path as path_utils;
4
- use std::fs;
5
-
6
- pub async fn remove_addon(name: String) -> Result<(), String> {
7
- let deva_dir = path_utils::ensure_deva_dir()?;
8
-
9
- // Helper to extract publisher from a slug like 'publisher.name'
10
- let extract_publisher = |s: &str| s.splitn(2, '.').next().unwrap_or("").to_string();
11
-
12
- // Try to find in config first (banks/plugins)
13
- if let Ok(config_path) = path_utils::get_devalang_config_path() {
14
- if let Some(mut config) = load_config(Some(&config_path)) {
15
- // BANKS
16
- if let Some(banks) = config.banks.as_mut() {
17
- if let Some(pos) = banks.iter().position(|b| {
18
- let slug = b.path.strip_prefix("devalang://bank/").unwrap_or(&b.path);
19
- // accept exact slug, exact path, or match by local name suffix (publisher/name or publisher.name)
20
- slug == name
21
- || b.path == name
22
- || slug.ends_with(&format!("/{}", name))
23
- || slug.ends_with(&format!(".{}", name))
24
- }) {
25
- let entry = banks.remove(pos);
26
- let slug = entry
27
- .path
28
- .strip_prefix("devalang://bank/")
29
- .unwrap_or(&entry.path)
30
- .to_string();
31
-
32
- // parse publisher/name from slug (support 'publisher/name' or 'publisher.name')
33
- let (publisher, local_name) = if slug.contains('/') {
34
- let mut it = slug.splitn(2, '/');
35
- (
36
- it.next().unwrap().to_string(),
37
- it.next().unwrap().to_string(),
38
- )
39
- } else if slug.contains('.') {
40
- let mut it = slug.splitn(2, '.');
41
- (
42
- it.next().unwrap().to_string(),
43
- it.next().unwrap().to_string(),
44
- )
45
- } else {
46
- return Err(format!("Cannot parse bank slug '{}'", slug));
47
- };
48
-
49
- let local_path = deva_dir.join("banks").join(&publisher).join(&local_name);
50
-
51
- if !local_path.exists() {
52
- return Err(format!(
53
- "Local files for bank '{}' not found at '{}', aborting",
54
- slug,
55
- local_path.display()
56
- ));
57
- }
58
-
59
- fs::remove_dir_all(&local_path)
60
- .map_err(|e| format!("Failed to remove addon files: {}", e))?;
61
-
62
- if let Err(e) = config.write_config(&config) {
63
- eprintln!("Warning: failed to write updated config: {}", e);
64
- }
65
-
66
- println!("✅ Bank '{}' removed (publisher '{}')", slug, publisher);
67
- return Ok(());
68
- }
69
- }
70
-
71
- // PLUGINS
72
- if let Some(plugins) = config.plugins.as_mut() {
73
- if let Some(pos) = plugins.iter().position(|p| {
74
- let slug = p.path.strip_prefix("devalang://plugin/").unwrap_or(&p.path);
75
- // accept exact slug, exact path, or match by local name suffix
76
- slug == name
77
- || p.path == name
78
- || slug.ends_with(&format!("/{}", name))
79
- || slug.ends_with(&format!(".{}", name))
80
- }) {
81
- let entry = plugins.remove(pos);
82
- let slug = entry
83
- .path
84
- .strip_prefix("devalang://plugin/")
85
- .unwrap_or(&entry.path)
86
- .to_string();
87
-
88
- // parse publisher/name from slug (support 'publisher/name' or 'publisher.name')
89
- let (publisher, local_name) = if slug.contains('/') {
90
- let mut it = slug.splitn(2, '/');
91
- (
92
- it.next().unwrap().to_string(),
93
- it.next().unwrap().to_string(),
94
- )
95
- } else if slug.contains('.') {
96
- let mut it = slug.splitn(2, '.');
97
- (
98
- it.next().unwrap().to_string(),
99
- it.next().unwrap().to_string(),
100
- )
101
- } else {
102
- return Err(format!("Cannot parse plugin slug '{}'", slug));
103
- };
104
-
105
- let local_path = deva_dir.join("plugins").join(&publisher).join(&local_name);
106
-
107
- if !local_path.exists() {
108
- return Err(format!(
109
- "Local files for plugin '{}' not found at '{}', aborting",
110
- slug,
111
- local_path.display()
112
- ));
113
- }
114
-
115
- fs::remove_dir_all(&local_path)
116
- .map_err(|e| format!("Failed to remove addon files: {}", e))?;
117
-
118
- if let Err(e) = config.write_config(&config) {
119
- eprintln!("Warning: failed to write updated config: {}", e);
120
- }
121
-
122
- println!("✅ Plugin '{}' removed (publisher '{}')", slug, publisher);
123
- return Ok(());
124
- }
125
- }
126
- }
127
- }
128
-
129
- // Not found in config: search filesystem under .deva and infer type
130
- let dirs = ["banks", "plugins", "presets", "templates"];
131
- for &d in &dirs {
132
- let folder = deva_dir.join(d);
133
- if !folder.exists() {
134
- continue;
135
- }
136
-
137
- // If name looks like a slug (contains '.' or '/'), parse publisher and name and try candidate paths
138
- if name.contains('.') || name.contains('/') {
139
- let (publisher, local_name) = if name.contains('/') {
140
- let mut it = name.splitn(2, '/');
141
- (
142
- it.next().unwrap().to_string(),
143
- it.next().unwrap().to_string(),
144
- )
145
- } else {
146
- let mut it = name.splitn(2, '.');
147
- (
148
- it.next().unwrap().to_string(),
149
- it.next().unwrap().to_string(),
150
- )
151
- };
152
-
153
- let candidate1 = folder.join(&publisher).join(&local_name);
154
- let candidate2 = folder.join(format!("{}.{}", publisher, local_name));
155
- let candidate3 = folder.join(&name);
156
-
157
- let candidate = if candidate1.exists() {
158
- candidate1
159
- } else if candidate2.exists() {
160
- candidate2
161
- } else {
162
- candidate3
163
- };
164
-
165
- if candidate.exists() {
166
- fs::remove_dir_all(&candidate)
167
- .map_err(|e| format!("Failed to remove addon files: {}", e))?;
168
-
169
- // also attempt to remove from config if possible
170
- if let Ok(config_path) = path_utils::get_devalang_config_path() {
171
- if let Some(mut config) = load_config(Some(&config_path)) {
172
- match d {
173
- "banks" => {
174
- if let Some(banks) = config.banks.as_mut() {
175
- let pattern1 =
176
- format!("devalang://bank/{}/{}", publisher, local_name);
177
- let pattern2 =
178
- format!("devalang://bank/{}.{}", publisher, local_name);
179
- banks.retain(|b| {
180
- b.path != pattern1
181
- && b.path != pattern2
182
- && !b.path.ends_with(&local_name)
183
- });
184
- }
185
- }
186
- "plugins" => {
187
- if let Some(plugins) = config.plugins.as_mut() {
188
- let pattern1 =
189
- format!("devalang://plugin/{}/{}", publisher, local_name);
190
- let pattern2 =
191
- format!("devalang://plugin/{}.{}", publisher, local_name);
192
- plugins.retain(|p| {
193
- p.path != pattern1
194
- && p.path != pattern2
195
- && !p.path.ends_with(&local_name)
196
- });
197
- }
198
- }
199
- _ => {}
200
- }
201
-
202
- if let Err(e) = config.write_config(&config) {
203
- eprintln!("Warning: failed to write updated config: {}", e);
204
- }
205
- }
206
- }
207
-
208
- println!(
209
- "✅ Addon '{}/{}' removed from .deva/{} (publisher '{}')",
210
- publisher, local_name, d, publisher
211
- );
212
- return Ok(());
213
- }
214
- }
215
-
216
- // Otherwise, scan directory entries: match exact name or suffix '.name'
217
- if let Ok(entries) = fs::read_dir(&folder) {
218
- for entry in entries.flatten() {
219
- if let Ok(file_type) = entry.file_type() {
220
- if !file_type.is_dir() {
221
- continue;
222
- }
223
- }
224
- let file_name = entry.file_name();
225
- let file_name = file_name.to_string_lossy();
226
- if file_name == name || file_name.ends_with(&format!(".{}", name)) {
227
- let slug = file_name.to_string();
228
- let publisher = extract_publisher(&slug);
229
- let path = entry.path();
230
- fs::remove_dir_all(&path)
231
- .map_err(|e| format!("Failed to remove addon files: {}", e))?;
232
-
233
- // try to remove from config when banks/plugins
234
- if let Ok(config_path) = path_utils::get_devalang_config_path() {
235
- if let Some(mut config) = load_config(Some(&config_path)) {
236
- match d {
237
- "banks" => {
238
- if let Some(banks) = config.banks.as_mut() {
239
- banks.retain(|b| {
240
- b.path != format!("devalang://bank/{}", slug)
241
- });
242
- }
243
- }
244
- "plugins" => {
245
- if let Some(plugins) = config.plugins.as_mut() {
246
- plugins.retain(|p| {
247
- p.path != format!("devalang://plugin/{}", slug)
248
- });
249
- }
250
- }
251
- _ => {}
252
- }
253
-
254
- if let Err(e) = config.write_config(&config) {
255
- eprintln!("Warning: failed to write updated config: {}", e);
256
- }
257
- }
258
- }
259
-
260
- println!(
261
- "✅ Addon '{}' removed from .deva/{} (publisher '{}')",
262
- slug, d, publisher
263
- );
264
- return Ok(());
265
- }
266
- }
267
- }
268
- }
269
-
270
- Err(format!("Addon '{}' not found", name))
271
- }
@@ -1,305 +0,0 @@
1
- use crate::config::ops::load_config;
2
- use crate::{
3
- cli::addon::{
4
- download::download_addon,
5
- metadata::{get_addon_from_api, get_addon_publisher_from_api},
6
- },
7
- web::cdn::get_cdn_url,
8
- };
9
- use devalang_core::config::driver::ProjectConfigExt;
10
- use devalang_types::AddonType;
11
- use devalang_utils::path as path_utils;
12
- use std::fs;
13
- use toml::Value as TomlValue;
14
-
15
- #[derive(serde::Deserialize)]
16
- pub struct AddonVersion {
17
- pub version: String,
18
- }
19
-
20
- async fn fetch_latest_version(
21
- addon_type: AddonType,
22
- addon_name: String,
23
- ) -> Result<AddonVersion, Box<dyn std::error::Error>> {
24
- let cdn_url = get_cdn_url();
25
-
26
- let addon_type = match addon_type {
27
- AddonType::Bank => "bank",
28
- AddonType::Plugin => "plugin",
29
- AddonType::Preset => "preset",
30
- AddonType::Template => "template",
31
- };
32
-
33
- let publisher_identifier = get_addon_publisher_from_api(&addon_name)
34
- .await
35
- .unwrap_or("unknown".to_string());
36
-
37
- let url = format!(
38
- "{}/{}/{}/{}/version",
39
- cdn_url, addon_type, publisher_identifier, addon_name
40
- );
41
-
42
- let response = reqwest::get(url).await?;
43
-
44
- if !response.status().is_success() {
45
- return Err(format!("❌ Failed to fetch version: HTTP {}", response.status()).into());
46
- }
47
-
48
- let bytes = response.bytes().await?;
49
-
50
- let version: AddonVersion = serde_json::from_slice(&bytes)?;
51
-
52
- Ok(version)
53
- }
54
-
55
- pub async fn update_addon(slug: String) -> Result<(), String> {
56
- let addon_metadata = get_addon_from_api(&slug).await?;
57
- let deva_dir = path_utils::ensure_deva_dir()?;
58
-
59
- // Represent the addon as "<publisher>.<addon>" for user-visible names
60
- let publisher_and_name = format!("{}.{}", addon_metadata.publisher, addon_metadata.name);
61
-
62
- match addon_metadata.addon_type {
63
- devalang_types::AddonType::Bank => {
64
- match fetch_latest_version(
65
- addon_metadata.addon_type.clone(),
66
- addon_metadata.name.clone(),
67
- )
68
- .await
69
- {
70
- Ok(latest) => {
71
- // Determine local version from bank.toml if available
72
- let local_bank_path = deva_dir
73
- .join("banks")
74
- .join(&addon_metadata.publisher)
75
- .join(&addon_metadata.name);
76
- let local_version = if local_bank_path.exists() {
77
- let bank_toml = local_bank_path.join("bank.toml");
78
- if bank_toml.exists() {
79
- if let Ok(content) = fs::read_to_string(&bank_toml) {
80
- if let Ok(parsed) =
81
- toml::from_str::<devalang_types::BankFile>(&content)
82
- {
83
- parsed.bank.version
84
- } else {
85
- String::new()
86
- }
87
- } else {
88
- String::new()
89
- }
90
- } else {
91
- String::new()
92
- }
93
- } else {
94
- String::new()
95
- };
96
-
97
- if local_version != latest.version {
98
- println!(
99
- "Updating bank '{}' from '{}' to '{}'...",
100
- publisher_and_name, local_version, latest.version
101
- );
102
-
103
- // remove existing folder if present
104
- let bank_dir = deva_dir
105
- .join("banks")
106
- .join(&addon_metadata.publisher)
107
- .join(&addon_metadata.name);
108
- if bank_dir.exists() {
109
- fs::remove_dir_all(&bank_dir)
110
- .map_err(|e| format!("Failed to remove old bank files: {}", e))?;
111
- }
112
-
113
- // download new (use publisher.addon as the external identifier)
114
- download_addon(&publisher_and_name, &addon_metadata).await?;
115
-
116
- // update config version when present
117
- if let Ok(config_path) = path_utils::get_devalang_config_path() {
118
- if let Some(mut config) = load_config(Some(&config_path)) {
119
- if let Some(banks) = config.banks.as_mut() {
120
- for bank in banks.iter_mut() {
121
- let name_in_path = bank
122
- .path
123
- .strip_prefix("devalang://bank/")
124
- .unwrap_or(&bank.path);
125
- }
126
-
127
- if let Err(e) = config.write_config(&config) {
128
- eprintln!("Warning: failed to write updated config: {}", e);
129
- }
130
- }
131
- }
132
- }
133
-
134
- println!(
135
- "✅ Bank '{}' updated to version '{}'",
136
- publisher_and_name, latest.version
137
- );
138
- } else {
139
- println!(
140
- "Bank '{}' is already up-to-date (version {})",
141
- publisher_and_name, latest.version
142
- );
143
- }
144
- }
145
- Err(e) => {
146
- return Err(format!(
147
- "Failed to fetch latest version for bank '{}': {}",
148
- publisher_and_name, e
149
- ));
150
- }
151
- }
152
- }
153
-
154
- devalang_types::AddonType::Plugin => {
155
- // Try to fetch latest version via CDN API; if available compare, otherwise fallback to redownload
156
- match fetch_latest_version(
157
- addon_metadata.addon_type.clone(),
158
- addon_metadata.name.clone(),
159
- )
160
- .await
161
- {
162
- Ok(latest) => {
163
- // Determine local plugin version by reading plugin.toml from preferred or fallback layout
164
- let preferred = deva_dir.join("plugins").join(format!(
165
- "{}/{}",
166
- addon_metadata.publisher, addon_metadata.name
167
- ));
168
- let fallback = deva_dir
169
- .join("plugins")
170
- .join(&addon_metadata.publisher)
171
- .join(&addon_metadata.name);
172
-
173
- let mut local_version = String::new();
174
- for candidate in [&preferred, &fallback] {
175
- let toml_path = candidate.join("plugin.toml");
176
- if toml_path.exists() {
177
- if let Ok(content) = fs::read_to_string(&toml_path) {
178
- if let Ok(value) = toml::from_str::<TomlValue>(&content) {
179
- if let Some(v) = value
180
- .get("plugin")
181
- .and_then(|p| p.get("version"))
182
- .and_then(|s| s.as_str())
183
- {
184
- local_version = v.to_string();
185
- }
186
- }
187
- }
188
- break;
189
- }
190
- }
191
-
192
- if local_version != latest.version {
193
- println!(
194
- "Updating plugin '{}' from '{}' to '{}'...",
195
- publisher_and_name, local_version, latest.version
196
- );
197
-
198
- // remove any existing layout
199
- if preferred.exists() {
200
- fs::remove_dir_all(&preferred)
201
- .map_err(|e| format!("Failed to remove old plugin files: {}", e))?;
202
- }
203
- if fallback.exists() {
204
- fs::remove_dir_all(&fallback)
205
- .map_err(|e| format!("Failed to remove old plugin files: {}", e))?;
206
- }
207
-
208
- // download new
209
- download_addon(&publisher_and_name, &addon_metadata).await?;
210
-
211
- // update config version when present
212
- if let Ok(config_path) = path_utils::get_devalang_config_path() {
213
- if let Some(mut config) = load_config(Some(&config_path)) {
214
- if let Some(plugins) = config.plugins.as_mut() {
215
- for p in plugins.iter_mut() {
216
- let name_in_path = p
217
- .path
218
- .strip_prefix("devalang://plugin/")
219
- .unwrap_or(&p.path);
220
- }
221
-
222
- if let Err(e) = config.write_config(&config) {
223
- eprintln!("Warning: failed to write updated config: {}", e);
224
- }
225
- }
226
- }
227
- }
228
-
229
- println!(
230
- "✅ Plugin '{}' updated to version '{}'",
231
- publisher_and_name, latest.version
232
- );
233
- } else {
234
- println!(
235
- "Plugin '{}' is already up-to-date (version {})",
236
- publisher_and_name, latest.version
237
- );
238
- }
239
- }
240
- Err(_) => {
241
- // Fallback: redownload everything
242
- println!(
243
- "No version info for plugin '{}', redownloading to ensure latest.",
244
- publisher_and_name
245
- );
246
-
247
- let plugin_dir = deva_dir
248
- .join("plugins")
249
- .join(&addon_metadata.publisher)
250
- .join(&addon_metadata.name);
251
- if plugin_dir.exists() {
252
- fs::remove_dir_all(&plugin_dir)
253
- .map_err(|e| format!("Failed to remove old plugin files: {}", e))?;
254
- }
255
-
256
- download_addon(&publisher_and_name, &addon_metadata).await?;
257
-
258
- // clear version in config (unknown)
259
- if let Ok(config_path) = path_utils::get_devalang_config_path() {
260
- if let Some(mut config) = load_config(Some(&config_path)) {
261
- if let Some(plugins) = config.plugins.as_mut() {
262
- for p in plugins.iter_mut() {
263
- let name_in_path = p
264
- .path
265
- .strip_prefix("devalang://plugin/")
266
- .unwrap_or(&p.path);
267
- }
268
-
269
- if let Err(e) = config.write_config(&config) {
270
- eprintln!("Warning: failed to write updated config: {}", e);
271
- }
272
- }
273
- }
274
- }
275
-
276
- println!("✅ Plugin '{}' updated", publisher_and_name);
277
- }
278
- }
279
- }
280
-
281
- devalang_types::AddonType::Preset | devalang_types::AddonType::Template => {
282
- println!(
283
- "Update for presets/templates is not yet implemented; reinstalling to be safe."
284
- );
285
- let target_dir = match addon_metadata.addon_type {
286
- devalang_types::AddonType::Preset => deva_dir.join("presets"),
287
- _ => deva_dir.join("templates"),
288
- };
289
-
290
- let candidate = target_dir
291
- .join(&addon_metadata.publisher)
292
- .join(&addon_metadata.name);
293
- if candidate.exists() {
294
- fs::remove_dir_all(&candidate)
295
- .map_err(|e| format!("Failed to remove old files: {}", e))?;
296
- }
297
-
298
- // use publisher.addon representation for user-facing messaging
299
- download_addon(&publisher_and_name, &addon_metadata).await?;
300
- println!("✅ Addon '{}' updated (reinstalled)", publisher_and_name);
301
- }
302
- }
303
-
304
- Ok(())
305
- }
@@ -1,109 +0,0 @@
1
- use crate::{config::settings::get_user_config, web::forge::get_forge_api_url};
2
- use devalang_types::AddonType;
3
-
4
- pub async fn ask_api_for_signed_url(
5
- addon_type: AddonType,
6
- publisher: String,
7
- slug: &str,
8
- ) -> Result<String, String> {
9
- let forge_api_url = get_forge_api_url();
10
-
11
- use devalang_utils::logger::LogLevel;
12
- use devalang_utils::logger::Logger;
13
-
14
- // Require an authenticated user for addon installation: token must be present and non-empty
15
- let stored_token_opt = get_user_config().and_then(|cfg| {
16
- let t = cfg.session.clone();
17
- if t.trim().is_empty() { None } else { Some(t) }
18
- });
19
-
20
- if stored_token_opt.is_none() {
21
- let logger = Logger::new();
22
- let msg = "Authentication required — run `devalang login` to authenticate";
23
- logger.log_message(LogLevel::Error, msg);
24
- return Err("Authentication required: run 'devalang login' to authenticate".to_string());
25
- }
26
-
27
- // Build request URL. If publisher is empty, omit the publisher param so the API
28
- // can resolve publisher by addon name itself (server-side lookup).
29
- let kind = match addon_type {
30
- AddonType::Bank => "bank",
31
- AddonType::Plugin => "plugin",
32
- AddonType::Preset => "preset",
33
- AddonType::Template => "template",
34
- };
35
-
36
- let request_url = if let Some(token) = &stored_token_opt {
37
- if publisher.trim().is_empty() {
38
- format!(
39
- "{}/v1/addon/url?type={}&slug={}&token={}",
40
- forge_api_url, kind, slug, token
41
- )
42
- } else {
43
- format!(
44
- "{}/v1/addon/url?type={}&publisher={}&slug={}&token={}",
45
- forge_api_url, kind, publisher, slug, token
46
- )
47
- }
48
- } else {
49
- if publisher.trim().is_empty() {
50
- format!("{}/v1/addon/url?type={}&slug={}", forge_api_url, kind, slug)
51
- } else {
52
- format!(
53
- "{}/v1/addon/url?type={}&publisher={}&slug={}",
54
- forge_api_url, kind, publisher, slug
55
- )
56
- }
57
- };
58
-
59
- let mut headers = reqwest::header::HeaderMap::new();
60
- if let Some(token) = stored_token_opt {
61
- headers.insert(
62
- "Authorization",
63
- format!("Bearer {}", token).parse().unwrap(),
64
- );
65
- }
66
-
67
- let client: reqwest::Client = reqwest::Client::builder()
68
- .default_headers(headers)
69
- .build()
70
- .map_err(|_| "Failed to build HTTP client".to_string())?;
71
-
72
- let resp = client
73
- .get(&request_url)
74
- .send()
75
- .await
76
- .map_err(|e| format!("Failed to receive response: {}", e))?;
77
-
78
- let status = resp.status();
79
- let body_text = resp
80
- .text()
81
- .await
82
- .map_err(|e| format!("Failed to read response body: {}", e))?;
83
-
84
- // Try to parse JSON; if parsing fails, return body for diagnostics
85
- let json: serde_json::Value = match serde_json::from_str(&body_text) {
86
- Ok(v) => v,
87
- Err(_) => {
88
- return Err(format!(
89
- "Invalid JSON response (status {}): {}",
90
- status, body_text
91
- ));
92
- }
93
- };
94
-
95
- // Extract payload.url safely
96
- let signed_url_opt = json
97
- .get("payload")
98
- .and_then(|p| p.get("url"))
99
- .and_then(|u| u.as_str())
100
- .map(|s| s.to_string());
101
-
102
- if let Some(signed_url) = signed_url_opt {
103
- Ok(signed_url)
104
- } else {
105
- // Provide detailed diagnostics to help user understand why it's null
106
- let err_msg = format!("API returned no URL (status {}): {}", status, body_text);
107
- Err(err_msg)
108
- }
109
- }