@devaloop/devalang 0.0.1-beta.3 → 0.1.2

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 (346) hide show
  1. package/LICENSE +20 -20
  2. package/README.md +251 -221
  3. package/out-tsc/api.d.ts +180 -0
  4. package/out-tsc/api.d.ts.map +1 -0
  5. package/out-tsc/api.js +286 -0
  6. package/out-tsc/api.js.map +1 -0
  7. package/out-tsc/bin/index.d.ts +12 -0
  8. package/out-tsc/bin/index.d.ts.map +1 -0
  9. package/out-tsc/bin/index.js +20 -54
  10. package/out-tsc/bin/index.js.map +1 -0
  11. package/out-tsc/examples/basic-usage.d.ts +8 -0
  12. package/out-tsc/examples/basic-usage.d.ts.map +1 -0
  13. package/out-tsc/examples/basic-usage.js +113 -0
  14. package/out-tsc/examples/basic-usage.js.map +1 -0
  15. package/out-tsc/index.d.ts +19 -5
  16. package/out-tsc/index.d.ts.map +1 -0
  17. package/out-tsc/index.js +24 -6
  18. package/out-tsc/index.js.map +1 -0
  19. package/out-tsc/scripts/copy-wasm-dts.d.ts +7 -0
  20. package/out-tsc/scripts/copy-wasm-dts.d.ts.map +1 -0
  21. package/out-tsc/scripts/copy-wasm-dts.js +36 -32
  22. package/out-tsc/scripts/copy-wasm-dts.js.map +1 -0
  23. package/out-tsc/scripts/postinstall.d.ts +1 -0
  24. package/out-tsc/scripts/postinstall.d.ts.map +1 -0
  25. package/out-tsc/scripts/postinstall.js +4 -1
  26. package/out-tsc/scripts/postinstall.js.map +1 -0
  27. package/out-tsc/scripts/version/bump.d.ts +5 -1
  28. package/out-tsc/scripts/version/bump.d.ts.map +1 -0
  29. package/out-tsc/scripts/version/bump.js +122 -44
  30. package/out-tsc/scripts/version/bump.js.map +1 -0
  31. package/out-tsc/scripts/version/fetch.d.ts +12 -1
  32. package/out-tsc/scripts/version/fetch.d.ts.map +1 -0
  33. package/out-tsc/scripts/version/fetch.js +68 -24
  34. package/out-tsc/scripts/version/fetch.js.map +1 -0
  35. package/out-tsc/scripts/version/index.d.ts +6 -0
  36. package/out-tsc/scripts/version/index.d.ts.map +1 -0
  37. package/out-tsc/scripts/version/index.js +44 -22
  38. package/out-tsc/scripts/version/index.js.map +1 -0
  39. package/out-tsc/scripts/version/sync.d.ts +5 -1
  40. package/out-tsc/scripts/version/sync.d.ts.map +1 -0
  41. package/out-tsc/scripts/version/sync.js +95 -29
  42. package/out-tsc/scripts/version/sync.js.map +1 -0
  43. package/out-tsc/types.d.ts +68 -0
  44. package/out-tsc/types.d.ts.map +1 -0
  45. package/out-tsc/{core/types/value.js → types.js} +4 -0
  46. package/out-tsc/types.js.map +1 -0
  47. package/out-tsc/wasm.d.ts +8 -0
  48. package/out-tsc/wasm.d.ts.map +1 -0
  49. package/out-tsc/{core/index.js → wasm.js} +9 -6
  50. package/out-tsc/wasm.js.map +1 -0
  51. package/package.json +42 -42
  52. package/.cargo/config.toml +0 -2
  53. package/.devalang +0 -9
  54. package/.github/workflows/ci.yml +0 -103
  55. package/Cargo.toml +0 -84
  56. package/docs/CHANGELOG.md +0 -622
  57. package/docs/CONTRIBUTING.md +0 -101
  58. package/docs/ROADMAP.md +0 -38
  59. package/docs/TODO.md +0 -71
  60. package/examples/automation.deva +0 -42
  61. package/examples/bank.deva +0 -7
  62. package/examples/bus.deva +0 -10
  63. package/examples/chain.deva +0 -19
  64. package/examples/condition.deva +0 -20
  65. package/examples/duration.deva +0 -9
  66. package/examples/effect.deva +0 -2
  67. package/examples/events.deva +0 -12
  68. package/examples/filter.deva +0 -11
  69. package/examples/function.deva +0 -15
  70. package/examples/group.deva +0 -12
  71. package/examples/index.deva +0 -63
  72. package/examples/lfo.deva +0 -9
  73. package/examples/loop.deva +0 -10
  74. package/examples/pattern.deva +0 -8
  75. package/examples/plugin.deva +0 -16
  76. package/examples/routing.deva +0 -23
  77. package/examples/samples/hat-808.wav +0 -0
  78. package/examples/samples/kick-808.wav +0 -0
  79. package/examples/synth.deva +0 -24
  80. package/examples/synth_types.deva +0 -17
  81. package/examples/variables.deva +0 -9
  82. package/out-tsc/bin/project-version.json +0 -6
  83. package/out-tsc/core/functions/index.d.ts +0 -42
  84. package/out-tsc/core/functions/index.js +0 -87
  85. package/out-tsc/core/index.d.ts +0 -6
  86. package/out-tsc/core/types/index.d.ts +0 -4
  87. package/out-tsc/core/types/index.js +0 -20
  88. package/out-tsc/core/types/plugin.d.ts +0 -18
  89. package/out-tsc/core/types/plugin.js +0 -2
  90. package/out-tsc/core/types/result.d.ts +0 -27
  91. package/out-tsc/core/types/result.js +0 -2
  92. package/out-tsc/core/types/statement.d.ts +0 -106
  93. package/out-tsc/core/types/statement.js +0 -2
  94. package/out-tsc/core/types/value.d.ts +0 -43
  95. package/out-tsc/pkg/devalang_core.d.ts +0 -15
  96. package/out-tsc/pkg/devalang_core.js +0 -65
  97. package/out-tsc/pkg/devalang_core_bg.wasm.d.ts +0 -34
  98. package/out-tsc/scripts/version/copy-to-binary.d.ts +0 -1
  99. package/out-tsc/scripts/version/copy-to-binary.js +0 -79
  100. package/project-version.json +0 -6
  101. package/rust/bindings/Cargo.toml +0 -9
  102. package/rust/bindings/src/lib.rs +0 -86
  103. package/rust/cli/addon/commands.rs +0 -35
  104. package/rust/cli/addon/download.rs +0 -234
  105. package/rust/cli/addon/install.rs +0 -33
  106. package/rust/cli/addon/list.rs +0 -224
  107. package/rust/cli/addon/metadata.rs +0 -124
  108. package/rust/cli/addon/mod.rs +0 -8
  109. package/rust/cli/addon/remove.rs +0 -271
  110. package/rust/cli/addon/update.rs +0 -305
  111. package/rust/cli/addon/utils.rs +0 -109
  112. package/rust/cli/build/commands.rs +0 -153
  113. package/rust/cli/build/mod.rs +0 -2
  114. package/rust/cli/build/process.rs +0 -165
  115. package/rust/cli/check/mod.rs +0 -208
  116. package/rust/cli/discover/commands.rs +0 -275
  117. package/rust/cli/discover/config.rs +0 -109
  118. package/rust/cli/discover/fs.rs +0 -19
  119. package/rust/cli/discover/install.rs +0 -214
  120. package/rust/cli/discover/metadata.rs +0 -48
  121. package/rust/cli/discover/mod.rs +0 -5
  122. package/rust/cli/init/commands.rs +0 -88
  123. package/rust/cli/init/mod.rs +0 -1
  124. package/rust/cli/login/commands.rs +0 -124
  125. package/rust/cli/login/mod.rs +0 -1
  126. package/rust/cli/me/commands.rs +0 -52
  127. package/rust/cli/me/mod.rs +0 -1
  128. package/rust/cli/mod.rs +0 -12
  129. package/rust/cli/parser.rs +0 -320
  130. package/rust/cli/play/commands.rs +0 -375
  131. package/rust/cli/play/io.rs +0 -17
  132. package/rust/cli/play/mod.rs +0 -5
  133. package/rust/cli/play/process.rs +0 -159
  134. package/rust/cli/play/realtime.rs +0 -91
  135. package/rust/cli/play/utils.rs +0 -23
  136. package/rust/cli/telemetry/commands.rs +0 -22
  137. package/rust/cli/telemetry/event_creator.rs +0 -80
  138. package/rust/cli/telemetry/mod.rs +0 -3
  139. package/rust/cli/telemetry/send.rs +0 -51
  140. package/rust/cli/template/commands.rs +0 -69
  141. package/rust/cli/template/mod.rs +0 -1
  142. package/rust/cli/update/commands.rs +0 -6
  143. package/rust/cli/update/mod.rs +0 -1
  144. package/rust/config/driver.rs +0 -112
  145. package/rust/config/mod.rs +0 -3
  146. package/rust/config/ops.rs +0 -26
  147. package/rust/config/settings.rs +0 -101
  148. package/rust/core/audio/engine/driver.rs +0 -237
  149. package/rust/core/audio/engine/export.rs +0 -169
  150. package/rust/core/audio/engine/helpers.rs +0 -178
  151. package/rust/core/audio/engine/mod.rs +0 -56
  152. package/rust/core/audio/engine/notes/dsp.rs +0 -88
  153. package/rust/core/audio/engine/notes/mod.rs +0 -53
  154. package/rust/core/audio/engine/notes/params.rs +0 -294
  155. package/rust/core/audio/engine/sample/insert.rs +0 -300
  156. package/rust/core/audio/engine/sample/mod.rs +0 -40
  157. package/rust/core/audio/engine/sample/padding.rs +0 -170
  158. package/rust/core/audio/evaluator/condition.rs +0 -61
  159. package/rust/core/audio/evaluator/mod.rs +0 -9
  160. package/rust/core/audio/evaluator/numeric.rs +0 -152
  161. package/rust/core/audio/evaluator/rhs.rs +0 -16
  162. package/rust/core/audio/evaluator/string_expr.rs +0 -94
  163. package/rust/core/audio/interpreter/driver.rs +0 -574
  164. package/rust/core/audio/interpreter/mod.rs +0 -2
  165. package/rust/core/audio/interpreter/statements/arrow_call/interprete.rs +0 -179
  166. package/rust/core/audio/interpreter/statements/arrow_call/methods/chord.rs +0 -398
  167. package/rust/core/audio/interpreter/statements/arrow_call/methods/effects.rs +0 -323
  168. package/rust/core/audio/interpreter/statements/arrow_call/methods/mod.rs +0 -3
  169. package/rust/core/audio/interpreter/statements/arrow_call/methods/note.rs +0 -371
  170. package/rust/core/audio/interpreter/statements/arrow_call/mod.rs +0 -3
  171. package/rust/core/audio/interpreter/statements/arrow_call/types/arp.rs +0 -192
  172. package/rust/core/audio/interpreter/statements/arrow_call/types/mod.rs +0 -24
  173. package/rust/core/audio/interpreter/statements/arrow_call/types/pad.rs +0 -116
  174. package/rust/core/audio/interpreter/statements/arrow_call/types/pluck.rs +0 -97
  175. package/rust/core/audio/interpreter/statements/arrow_call/types/sub.rs +0 -100
  176. package/rust/core/audio/interpreter/statements/automate.rs +0 -16
  177. package/rust/core/audio/interpreter/statements/call.rs +0 -325
  178. package/rust/core/audio/interpreter/statements/condition.rs +0 -72
  179. package/rust/core/audio/interpreter/statements/function.rs +0 -24
  180. package/rust/core/audio/interpreter/statements/let_.rs +0 -36
  181. package/rust/core/audio/interpreter/statements/load.rs +0 -17
  182. package/rust/core/audio/interpreter/statements/loop_.rs +0 -115
  183. package/rust/core/audio/interpreter/statements/mod.rs +0 -12
  184. package/rust/core/audio/interpreter/statements/sleep.rs +0 -28
  185. package/rust/core/audio/interpreter/statements/spawn.rs +0 -302
  186. package/rust/core/audio/interpreter/statements/tempo.rs +0 -40
  187. package/rust/core/audio/interpreter/statements/trigger.rs +0 -242
  188. package/rust/core/audio/loader/mod.rs +0 -1
  189. package/rust/core/audio/loader/trigger.rs +0 -98
  190. package/rust/core/audio/mod.rs +0 -6
  191. package/rust/core/audio/player.rs +0 -70
  192. package/rust/core/audio/special/easing.rs +0 -189
  193. package/rust/core/audio/special/env.rs +0 -45
  194. package/rust/core/audio/special/math.rs +0 -134
  195. package/rust/core/audio/special/mod.rs +0 -9
  196. package/rust/core/audio/special/modulator.rs +0 -143
  197. package/rust/core/builder/mod.rs +0 -129
  198. package/rust/core/debugger/lexer.rs +0 -27
  199. package/rust/core/debugger/logs.rs +0 -52
  200. package/rust/core/debugger/mod.rs +0 -30
  201. package/rust/core/debugger/preprocessor.rs +0 -27
  202. package/rust/core/debugger/store.rs +0 -38
  203. package/rust/core/error/mod.rs +0 -269
  204. package/rust/core/lexer/driver.rs +0 -59
  205. package/rust/core/lexer/handler/arrow.rs +0 -82
  206. package/rust/core/lexer/handler/at.rs +0 -21
  207. package/rust/core/lexer/handler/brace.rs +0 -41
  208. package/rust/core/lexer/handler/colon.rs +0 -21
  209. package/rust/core/lexer/handler/comment.rs +0 -30
  210. package/rust/core/lexer/handler/dot.rs +0 -21
  211. package/rust/core/lexer/handler/driver.rs +0 -337
  212. package/rust/core/lexer/handler/identifier.rs +0 -47
  213. package/rust/core/lexer/handler/indent.rs +0 -66
  214. package/rust/core/lexer/handler/mod.rs +0 -15
  215. package/rust/core/lexer/handler/newline.rs +0 -23
  216. package/rust/core/lexer/handler/number.rs +0 -31
  217. package/rust/core/lexer/handler/operator.rs +0 -46
  218. package/rust/core/lexer/handler/parenthesis.rs +0 -41
  219. package/rust/core/lexer/handler/slash.rs +0 -21
  220. package/rust/core/lexer/handler/string.rs +0 -63
  221. package/rust/core/lexer/mod.rs +0 -3
  222. package/rust/core/lexer/token.rs +0 -91
  223. package/rust/core/mod.rs +0 -9
  224. package/rust/core/parser/driver/block.rs +0 -111
  225. package/rust/core/parser/driver/cursor.rs +0 -82
  226. package/rust/core/parser/driver/driver_impl.rs +0 -159
  227. package/rust/core/parser/driver/mod.rs +0 -6
  228. package/rust/core/parser/driver/parse_array.rs +0 -120
  229. package/rust/core/parser/driver/parse_map.rs +0 -247
  230. package/rust/core/parser/driver/parser.rs +0 -160
  231. package/rust/core/parser/handler/arrow_call.rs +0 -328
  232. package/rust/core/parser/handler/at.rs +0 -279
  233. package/rust/core/parser/handler/bank.rs +0 -104
  234. package/rust/core/parser/handler/condition.rs +0 -83
  235. package/rust/core/parser/handler/dot.rs +0 -148
  236. package/rust/core/parser/handler/identifier/automate.rs +0 -254
  237. package/rust/core/parser/handler/identifier/call.rs +0 -91
  238. package/rust/core/parser/handler/identifier/emit.rs +0 -70
  239. package/rust/core/parser/handler/identifier/function.rs +0 -113
  240. package/rust/core/parser/handler/identifier/group.rs +0 -89
  241. package/rust/core/parser/handler/identifier/let_.rs +0 -173
  242. package/rust/core/parser/handler/identifier/mod.rs +0 -55
  243. package/rust/core/parser/handler/identifier/on.rs +0 -107
  244. package/rust/core/parser/handler/identifier/print.rs +0 -49
  245. package/rust/core/parser/handler/identifier/sleep.rs +0 -96
  246. package/rust/core/parser/handler/identifier/spawn.rs +0 -91
  247. package/rust/core/parser/handler/identifier/synth.rs +0 -171
  248. package/rust/core/parser/handler/loop_.rs +0 -194
  249. package/rust/core/parser/handler/mod.rs +0 -9
  250. package/rust/core/parser/handler/pattern.rs +0 -97
  251. package/rust/core/parser/handler/tempo.rs +0 -105
  252. package/rust/core/parser/mod.rs +0 -3
  253. package/rust/core/parser/statement.rs +0 -10
  254. package/rust/core/plugin/loader.rs +0 -137
  255. package/rust/core/plugin/mod.rs +0 -2
  256. package/rust/core/plugin/runner/mod.rs +0 -11
  257. package/rust/core/plugin/runner/non_wasm.rs +0 -481
  258. package/rust/core/plugin/runner/wasm32.rs +0 -44
  259. package/rust/core/preprocessor/loader/inject.rs +0 -313
  260. package/rust/core/preprocessor/loader/loader_helpers.rs +0 -110
  261. package/rust/core/preprocessor/loader/mod.rs +0 -235
  262. package/rust/core/preprocessor/mod.rs +0 -4
  263. package/rust/core/preprocessor/module.rs +0 -55
  264. package/rust/core/preprocessor/processor/handlers.rs +0 -107
  265. package/rust/core/preprocessor/processor/mod.rs +0 -1
  266. package/rust/core/preprocessor/resolver/bank.rs +0 -49
  267. package/rust/core/preprocessor/resolver/call.rs +0 -124
  268. package/rust/core/preprocessor/resolver/condition.rs +0 -95
  269. package/rust/core/preprocessor/resolver/driver.rs +0 -324
  270. package/rust/core/preprocessor/resolver/function.rs +0 -69
  271. package/rust/core/preprocessor/resolver/group.rs +0 -122
  272. package/rust/core/preprocessor/resolver/let_.rs +0 -32
  273. package/rust/core/preprocessor/resolver/loop_.rs +0 -318
  274. package/rust/core/preprocessor/resolver/mod.rs +0 -16
  275. package/rust/core/preprocessor/resolver/pattern.rs +0 -95
  276. package/rust/core/preprocessor/resolver/spawn.rs +0 -99
  277. package/rust/core/preprocessor/resolver/synth.rs +0 -54
  278. package/rust/core/preprocessor/resolver/tempo.rs +0 -48
  279. package/rust/core/preprocessor/resolver/trigger.rs +0 -116
  280. package/rust/core/preprocessor/resolver/value.rs +0 -176
  281. package/rust/core/store/global.rs +0 -57
  282. package/rust/core/store/mod.rs +0 -1
  283. package/rust/lib.rs +0 -323
  284. package/rust/macros/Cargo.toml +0 -14
  285. package/rust/macros/src/lib.rs +0 -52
  286. package/rust/main.rs +0 -557
  287. package/rust/types/Cargo.toml +0 -11
  288. package/rust/types/src/addons.rs +0 -57
  289. package/rust/types/src/ast.rs +0 -202
  290. package/rust/types/src/config.rs +0 -82
  291. package/rust/types/src/lib.rs +0 -15
  292. package/rust/types/src/plugin.rs +0 -20
  293. package/rust/types/src/store.rs +0 -139
  294. package/rust/types/src/telemetry.rs +0 -85
  295. package/rust/utils/Cargo.toml +0 -29
  296. package/rust/utils/src/error.rs +0 -186
  297. package/rust/utils/src/file.rs +0 -477
  298. package/rust/utils/src/first_usage.rs +0 -97
  299. package/rust/utils/src/lib.rs +0 -9
  300. package/rust/utils/src/logger.rs +0 -200
  301. package/rust/utils/src/path.rs +0 -158
  302. package/rust/utils/src/signature.rs +0 -41
  303. package/rust/utils/src/spinner.rs +0 -20
  304. package/rust/utils/src/version.rs +0 -58
  305. package/rust/utils/src/watcher.rs +0 -46
  306. package/rust/web/api.rs +0 -5
  307. package/rust/web/auth.rs +0 -5
  308. package/rust/web/cdn.rs +0 -34
  309. package/rust/web/forge.rs +0 -5
  310. package/rust/web/mod.rs +0 -5
  311. package/rust/web/sso.rs +0 -5
  312. package/templates/minimal/.devalang +0 -5
  313. package/templates/minimal/README.md +0 -218
  314. package/templates/minimal/src/index.deva +0 -2
  315. package/templates/welcome/.devalang +0 -5
  316. package/templates/welcome/README.md +0 -218
  317. package/templates/welcome/samples/kick-808.wav +0 -0
  318. package/templates/welcome/src/index.deva +0 -61
  319. package/templates/welcome/src/variables.deva +0 -3
  320. package/tests/integration.rs +0 -21
  321. package/tests/rust/cli_check_build.rs +0 -21
  322. package/tests/rust/cli_help.rs +0 -12
  323. package/tests/rust/cli_template_list.rs +0 -10
  324. package/tests/rust/cli_version.rs +0 -11
  325. package/tests/typescript/index.spec.ts +0 -136
  326. package/tests/typescript/playhead.spec.ts +0 -36
  327. package/tests/typescript/render_e2e.spec.ts +0 -77
  328. package/tsconfig.json +0 -115
  329. package/typescript/bin/index.ts +0 -28
  330. package/typescript/core/functions/index.ts +0 -94
  331. package/typescript/core/index.ts +0 -6
  332. package/typescript/core/types/index.ts +0 -4
  333. package/typescript/core/types/plugin.ts +0 -19
  334. package/typescript/core/types/result.ts +0 -29
  335. package/typescript/core/types/statement.ts +0 -47
  336. package/typescript/core/types/value.ts +0 -29
  337. package/typescript/index.ts +0 -8
  338. package/typescript/pkg/devalang_core.d.ts +0 -4
  339. package/typescript/pkg/devalang_core.ts +0 -65
  340. package/typescript/scripts/copy-wasm-dts.ts +0 -41
  341. package/typescript/scripts/postinstall.ts +0 -85
  342. package/typescript/scripts/version/bump.ts +0 -44
  343. package/typescript/scripts/version/copy-to-binary.ts +0 -82
  344. package/typescript/scripts/version/fetch.ts +0 -18
  345. package/typescript/scripts/version/index.ts +0 -25
  346. 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
- }