rune-lab 0.4.2-beta.1 → 0.4.2-beta.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 (249) hide show
  1. package/.gitignore +12 -0
  2. package/deno.json +42 -5
  3. package/justfile +5 -0
  4. package/package.json +2 -22
  5. package/scripts/build_pkg.ts +57 -0
  6. package/scripts/ci.just +26 -0
  7. package/scripts/deploy.just +26 -0
  8. package/scripts/dev.just +4 -0
  9. package/scripts/inject.just +72 -0
  10. package/src/app.d.ts +13 -0
  11. package/src/app.html +12 -0
  12. package/src/lib/RuneProvider.svelte +105 -0
  13. package/src/lib/i18n/message-resolver.test.ts +103 -0
  14. package/src/lib/i18n/message-resolver.ts +89 -0
  15. package/src/lib/i18n/project.inlang/settings.json +26 -0
  16. package/src/lib/i18n/translations/ar.json +89 -0
  17. package/src/lib/i18n/translations/de.json +89 -0
  18. package/src/lib/i18n/translations/en.json +89 -0
  19. package/src/lib/i18n/translations/es.json +89 -0
  20. package/src/lib/i18n/translations/fr.json +89 -0
  21. package/src/lib/i18n/translations/hi.json +89 -0
  22. package/src/lib/i18n/translations/it.json +89 -0
  23. package/src/lib/i18n/translations/ja.json +89 -0
  24. package/src/lib/i18n/translations/ko.json +89 -0
  25. package/src/lib/i18n/translations/pt.json +89 -0
  26. package/src/lib/i18n/translations/ru.json +89 -0
  27. package/src/lib/i18n/translations/vi.json +89 -0
  28. package/src/lib/i18n/translations/zh.json +89 -0
  29. package/src/lib/kernel/deno.json +5 -0
  30. package/src/lib/kernel/src/actions/portal.ts +41 -0
  31. package/src/lib/kernel/src/actions/shortcut-listener.ts +50 -0
  32. package/src/lib/kernel/src/context/app.svelte.ts +98 -0
  33. package/src/{kernel → lib/kernel}/src/context/context.ts +18 -5
  34. package/src/lib/kernel/src/context/stores.svelte.ts +96 -0
  35. package/src/lib/kernel/src/context/types.ts +110 -0
  36. package/src/lib/kernel/src/context/useRuneLab.ts +38 -0
  37. package/src/lib/kernel/src/mod.ts +13 -0
  38. package/src/lib/kernel/src/persistence/createConfigStore.svelte.ts +120 -0
  39. package/src/lib/kernel/src/persistence/drivers.test.ts +95 -0
  40. package/src/lib/kernel/src/persistence/drivers.ts +77 -0
  41. package/src/lib/kernel/src/persistence/provider.test.ts +58 -0
  42. package/src/lib/kernel/src/persistence/provider.ts +58 -0
  43. package/src/lib/kernel/src/persistence/types.ts +19 -0
  44. package/src/lib/kernel/src/persistence/usePersistence.ts +9 -0
  45. package/src/lib/kernel/src/registry/mod.ts +221 -0
  46. package/src/lib/kernel/src/registry/registry.test.ts +162 -0
  47. package/src/lib/kernel/src/tokens/props.ts +94 -0
  48. package/src/lib/mod.ts +10 -0
  49. package/src/lib/runes/layout/deno.json +5 -0
  50. package/src/lib/runes/layout/src/APP_CONFIGURATIONS.ts +56 -0
  51. package/src/lib/runes/layout/src/AppSettingSelector.svelte +177 -0
  52. package/src/lib/runes/layout/src/ConnectedNavigationPanel.svelte +26 -0
  53. package/src/lib/runes/layout/src/ConnectedWorkspaceStrip.svelte +22 -0
  54. package/src/lib/runes/layout/src/ContentArea.svelte +19 -0
  55. package/src/lib/runes/layout/src/DetailPanel.svelte +12 -0
  56. package/src/lib/runes/layout/src/Icon.svelte +7 -0
  57. package/src/lib/runes/layout/src/LanguageSelector.svelte +45 -0
  58. package/src/lib/runes/layout/src/NavigationPanel.svelte +117 -0
  59. package/src/lib/runes/layout/src/ResourceSelector.svelte +90 -0
  60. package/src/lib/runes/layout/src/ThemeSelector.svelte +50 -0
  61. package/src/lib/runes/layout/src/WorkspaceLayout.svelte +252 -0
  62. package/src/lib/runes/layout/src/WorkspaceStrip.svelte +72 -0
  63. package/src/lib/runes/layout/src/connection-factory.ts +95 -0
  64. package/src/lib/runes/layout/src/language.svelte.ts +44 -0
  65. package/src/lib/runes/layout/src/mod.ts +71 -0
  66. package/src/lib/runes/layout/src/store.svelte.ts +142 -0
  67. package/src/lib/runes/layout/src/theme.svelte.ts +73 -0
  68. package/src/lib/runes/layout/src/types.ts +11 -0
  69. package/src/lib/runes/palettes/deno.json +8 -0
  70. package/src/lib/runes/palettes/src/commands/CommandPalette.svelte +227 -0
  71. package/src/lib/runes/palettes/src/commands/mod.ts +2 -0
  72. package/src/lib/runes/palettes/src/commands/store.svelte.ts +80 -0
  73. package/src/lib/runes/palettes/src/mod.ts +51 -0
  74. package/src/lib/runes/palettes/src/notifications/NotificationBell.svelte +89 -0
  75. package/src/lib/runes/palettes/src/notifications/Toaster.svelte +100 -0
  76. package/src/lib/runes/palettes/src/notifications/bridge.ts +56 -0
  77. package/src/lib/runes/palettes/src/notifications/mod.ts +4 -0
  78. package/src/lib/runes/palettes/src/notifications/store.svelte.ts +58 -0
  79. package/src/lib/runes/palettes/src/shortcuts/ShortcutPalette.svelte +243 -0
  80. package/src/lib/runes/palettes/src/shortcuts/mod.ts +4 -0
  81. package/src/lib/runes/palettes/src/shortcuts/store.svelte.ts +85 -0
  82. package/src/lib/runes/palettes/src/shortcuts/types.ts +4 -0
  83. package/src/lib/runes/palettes/src/shortcuts/useShortcuts.ts +85 -0
  84. package/src/lib/runes/plugins/money/deno.json +8 -0
  85. package/src/lib/runes/plugins/money/src/CurrencySelector.svelte +41 -0
  86. package/src/lib/runes/plugins/money/src/MoneyDisplay.svelte +142 -0
  87. package/src/lib/runes/plugins/money/src/MoneyInput.svelte +208 -0
  88. package/src/lib/runes/plugins/money/src/currency.svelte.ts +95 -0
  89. package/src/lib/runes/plugins/money/src/currency.test.ts +40 -0
  90. package/src/lib/runes/plugins/money/src/exchange-rate.svelte.ts +176 -0
  91. package/src/lib/runes/plugins/money/src/exchange-rate.test.ts +95 -0
  92. package/src/lib/runes/plugins/money/src/mod.ts +79 -0
  93. package/src/lib/runes/plugins/money/src/money-primitive.test.ts +217 -0
  94. package/src/lib/runes/plugins/money/src/money-primitive.ts +220 -0
  95. package/src/lib/runes/plugins/money/src/money.test.ts +183 -0
  96. package/src/lib/runes/plugins/money/src/money.ts +382 -0
  97. package/src/lib/runes/plugins/money/src/strategies.test.ts +143 -0
  98. package/src/lib/runes/plugins/money/src/strategies.ts +95 -0
  99. package/src/lib/runes/plugins/money/src/types.ts +27 -0
  100. package/src/lib/runes/plugins/money/src/useMoney.ts +261 -0
  101. package/src/lib/runes/plugins/money/src/useMoneyFilter.ts +132 -0
  102. package/src/routes/+page.svelte +3 -0
  103. package/tsconfig.json +41 -0
  104. package/vite.config.ts +22 -0
  105. package/src/RuneProvider.ts +0 -104
  106. package/src/_virtual/_rolldown/runtime.ts +0 -14
  107. package/src/i18n/paraglide/messages/_index.ts +0 -178
  108. package/src/i18n/paraglide/messages/abyss.ts +0 -45
  109. package/src/i18n/paraglide/messages/acid.ts +0 -45
  110. package/src/i18n/paraglide/messages/active_toasts.ts +0 -45
  111. package/src/i18n/paraglide/messages/aed3.ts +0 -45
  112. package/src/i18n/paraglide/messages/all_currencies.ts +0 -45
  113. package/src/i18n/paraglide/messages/all_languages.ts +0 -45
  114. package/src/i18n/paraglide/messages/all_themes.ts +0 -45
  115. package/src/i18n/paraglide/messages/api_status.ts +0 -45
  116. package/src/i18n/paraglide/messages/app_info.ts +0 -45
  117. package/src/i18n/paraglide/messages/appearance.ts +0 -45
  118. package/src/i18n/paraglide/messages/aqua.ts +0 -45
  119. package/src/i18n/paraglide/messages/ar.ts +0 -45
  120. package/src/i18n/paraglide/messages/autumn.ts +0 -45
  121. package/src/i18n/paraglide/messages/black.ts +0 -45
  122. package/src/i18n/paraglide/messages/brl3.ts +0 -45
  123. package/src/i18n/paraglide/messages/bumblebee.ts +0 -45
  124. package/src/i18n/paraglide/messages/business.ts +0 -45
  125. package/src/i18n/paraglide/messages/cad3.ts +0 -45
  126. package/src/i18n/paraglide/messages/caramellatte.ts +0 -45
  127. package/src/i18n/paraglide/messages/cmyk.ts +0 -45
  128. package/src/i18n/paraglide/messages/cny3.ts +0 -45
  129. package/src/i18n/paraglide/messages/coffee.ts +0 -45
  130. package/src/i18n/paraglide/messages/commands_label.ts +0 -45
  131. package/src/i18n/paraglide/messages/corporate.ts +0 -45
  132. package/src/i18n/paraglide/messages/cupcake.ts +0 -45
  133. package/src/i18n/paraglide/messages/currency.ts +0 -45
  134. package/src/i18n/paraglide/messages/current_currency.ts +0 -45
  135. package/src/i18n/paraglide/messages/current_language.ts +0 -45
  136. package/src/i18n/paraglide/messages/current_theme.ts +0 -45
  137. package/src/i18n/paraglide/messages/currently_in_queue.ts +0 -45
  138. package/src/i18n/paraglide/messages/cyberpunk.ts +0 -45
  139. package/src/i18n/paraglide/messages/dark.ts +0 -45
  140. package/src/i18n/paraglide/messages/de.ts +0 -45
  141. package/src/i18n/paraglide/messages/dim.ts +0 -45
  142. package/src/i18n/paraglide/messages/dracula.ts +0 -45
  143. package/src/i18n/paraglide/messages/emerald.ts +0 -45
  144. package/src/i18n/paraglide/messages/en.ts +0 -45
  145. package/src/i18n/paraglide/messages/es.ts +0 -45
  146. package/src/i18n/paraglide/messages/eur3.ts +0 -45
  147. package/src/i18n/paraglide/messages/extended_controls.ts +0 -45
  148. package/src/i18n/paraglide/messages/fantasy.ts +0 -45
  149. package/src/i18n/paraglide/messages/forest.ts +0 -45
  150. package/src/i18n/paraglide/messages/fr.ts +0 -45
  151. package/src/i18n/paraglide/messages/garden.ts +0 -45
  152. package/src/i18n/paraglide/messages/gbp3.ts +0 -45
  153. package/src/i18n/paraglide/messages/halloween.ts +0 -45
  154. package/src/i18n/paraglide/messages/hello_world.ts +0 -45
  155. package/src/i18n/paraglide/messages/hi.ts +0 -45
  156. package/src/i18n/paraglide/messages/inr3.ts +0 -45
  157. package/src/i18n/paraglide/messages/it.ts +0 -45
  158. package/src/i18n/paraglide/messages/ja.ts +0 -45
  159. package/src/i18n/paraglide/messages/jpy3.ts +0 -45
  160. package/src/i18n/paraglide/messages/ko.ts +0 -45
  161. package/src/i18n/paraglide/messages/krw3.ts +0 -45
  162. package/src/i18n/paraglide/messages/languages.ts +0 -45
  163. package/src/i18n/paraglide/messages/lemonade.ts +0 -45
  164. package/src/i18n/paraglide/messages/light.ts +0 -45
  165. package/src/i18n/paraglide/messages/live_store_dashboard.ts +0 -45
  166. package/src/i18n/paraglide/messages/localization.ts +0 -45
  167. package/src/i18n/paraglide/messages/lofi.ts +0 -45
  168. package/src/i18n/paraglide/messages/luxury.ts +0 -45
  169. package/src/i18n/paraglide/messages/mxn3.ts +0 -45
  170. package/src/i18n/paraglide/messages/name_label.ts +0 -45
  171. package/src/i18n/paraglide/messages/night.ts +0 -45
  172. package/src/i18n/paraglide/messages/nord.ts +0 -45
  173. package/src/i18n/paraglide/messages/pastel.ts +0 -45
  174. package/src/i18n/paraglide/messages/pt.ts +0 -45
  175. package/src/i18n/paraglide/messages/real_time_monitor_desc.ts +0 -47
  176. package/src/i18n/paraglide/messages/registered_in_registry.ts +0 -45
  177. package/src/i18n/paraglide/messages/retro.ts +0 -45
  178. package/src/i18n/paraglide/messages/ru.ts +0 -45
  179. package/src/i18n/paraglide/messages/silk.ts +0 -45
  180. package/src/i18n/paraglide/messages/state_label.ts +0 -45
  181. package/src/i18n/paraglide/messages/sunset.ts +0 -45
  182. package/src/i18n/paraglide/messages/synthwave.ts +0 -45
  183. package/src/i18n/paraglide/messages/system.ts +0 -45
  184. package/src/i18n/paraglide/messages/theme.ts +0 -45
  185. package/src/i18n/paraglide/messages/themes.ts +0 -45
  186. package/src/i18n/paraglide/messages/url_label.ts +0 -45
  187. package/src/i18n/paraglide/messages/usd3.ts +0 -45
  188. package/src/i18n/paraglide/messages/valentine.ts +0 -45
  189. package/src/i18n/paraglide/messages/version_label.ts +0 -45
  190. package/src/i18n/paraglide/messages/vi.ts +0 -45
  191. package/src/i18n/paraglide/messages/winter.ts +0 -45
  192. package/src/i18n/paraglide/messages/wireframe.ts +0 -45
  193. package/src/i18n/paraglide/messages/zh.ts +0 -45
  194. package/src/i18n/paraglide/messages.ts +0 -180
  195. package/src/i18n/paraglide/runtime.ts +0 -147
  196. package/src/kernel/src/actions/portal.ts +0 -20
  197. package/src/kernel/src/actions/shortcut-listener.ts +0 -22
  198. package/src/kernel/src/context/app.svelte.ts +0 -111
  199. package/src/kernel/src/context/stores.svelte.ts +0 -56
  200. package/src/kernel/src/mod.ts +0 -11
  201. package/src/kernel/src/persistence/createConfigStore.svelte.ts +0 -57
  202. package/src/kernel/src/persistence/drivers.ts +0 -59
  203. package/src/kernel/src/persistence/provider.ts +0 -22
  204. package/src/kernel/src/persistence/usePersistence.ts +0 -9
  205. package/src/kernel/src/registry/mod.ts +0 -68
  206. package/src/kernel/src/tokens/props.ts +0 -9
  207. package/src/mod.ts +0 -243
  208. package/src/node_modules/.deno/dinero.js@2.0.2/node_modules/dinero.js/dist/esm/currencies/index.ts +0 -48
  209. package/src/node_modules/.deno/dinero.js@2.0.2/node_modules/dinero.js/dist/esm/index.ts +0 -26
  210. package/src/node_modules/.deno/dinero.js@2.0.2/node_modules/dinero.js/dist/esm/trimScale-C3-DjbPM.ts +0 -246
  211. package/src/rune-lab.css +0 -44
  212. package/src/runes/layout/src/APP_CONFIGURATIONS.ts +0 -26
  213. package/src/runes/layout/src/AppSettingSelector.ts +0 -151
  214. package/src/runes/layout/src/ContentArea.ts +0 -22
  215. package/src/runes/layout/src/DetailPanel.ts +0 -10
  216. package/src/runes/layout/src/Icon.ts +0 -16
  217. package/src/runes/layout/src/LanguageSelector.ts +0 -67
  218. package/src/runes/layout/src/NavigationPanel.ts +0 -162
  219. package/src/runes/layout/src/ResourceSelector.ts +0 -63
  220. package/src/runes/layout/src/ThemeSelector.ts +0 -63
  221. package/src/runes/layout/src/WorkspaceLayout.ts +0 -210
  222. package/src/runes/layout/src/WorkspaceStrip.ts +0 -107
  223. package/src/runes/layout/src/connection-factory.ts +0 -29
  224. package/src/runes/layout/src/language.svelte.ts +0 -68
  225. package/src/runes/layout/src/mod.ts +0 -56
  226. package/src/runes/layout/src/store.svelte.ts +0 -133
  227. package/src/runes/layout/src/theme.svelte.ts +0 -61
  228. package/src/runes/layout/src/types.ts +0 -2
  229. package/src/runes/palettes/src/commands/CommandPalette.ts +0 -241
  230. package/src/runes/palettes/src/commands/mod.ts +0 -3
  231. package/src/runes/palettes/src/commands/store.svelte.ts +0 -48
  232. package/src/runes/palettes/src/mod.ts +0 -64
  233. package/src/runes/palettes/src/notifications/NotificationBell.ts +0 -51
  234. package/src/runes/palettes/src/notifications/Toaster.ts +0 -82
  235. package/src/runes/palettes/src/notifications/bridge.ts +0 -21
  236. package/src/runes/palettes/src/notifications/mod.ts +0 -5
  237. package/src/runes/palettes/src/notifications/store.svelte.ts +0 -46
  238. package/src/runes/palettes/src/shortcuts/ShortcutPalette.ts +0 -208
  239. package/src/runes/palettes/src/shortcuts/mod.ts +0 -5
  240. package/src/runes/palettes/src/shortcuts/store.svelte.ts +0 -83
  241. package/src/runes/palettes/src/shortcuts/useShortcuts.ts +0 -32
  242. package/src/runes/plugins/money/src/currency.svelte.ts +0 -98
  243. package/src/runes/plugins/money/src/exchange-rate.svelte.ts +0 -97
  244. package/src/runes/plugins/money/src/mod.ts +0 -46
  245. package/src/runes/plugins/money/src/money-primitive.ts +0 -83
  246. package/src/runes/plugins/money/src/money.ts +0 -202
  247. package/src/runes/plugins/money/src/strategies.ts +0 -35
  248. package/src/runes/plugins/money/src/useMoney.ts +0 -80
  249. package/src/runes/plugins/money/src/useMoneyFilter.ts +0 -66
package/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ # all that start with a dot except .gitignore
2
+ .*
3
+ !.gitignore
4
+
5
+ # lock files (from various package managers)
6
+ *.lock
7
+
8
+ # web-generated files
9
+ node_modules
10
+ dist
11
+ lab
12
+ build
package/deno.json CHANGED
@@ -1,13 +1,50 @@
1
1
  {
2
2
  "name": "@yrrrrrf/rune-lab",
3
- "version": "0.4.2-beta.1",
3
+ "version": "0.4.2-beta.2",
4
4
  "description": "Modern toolkit for Svelte 5 Runes applications.",
5
+ "type": "module",
5
6
  "license": "MIT",
6
- "exports": {
7
- ".": "./src/mod.ts"
8
- },
7
+ "readme": "./README.md",
8
+ "author": "Fernando Bryan Reza Campos",
9
9
  "repository": {
10
10
  "type": "git",
11
11
  "url": "git+https://github.com/Yrrrrrf/rune-lab.git"
12
- }
12
+ },
13
+ "exports": {
14
+ ".": "./src/lib/mod.ts"
15
+ },
16
+ "nodeModulesDir": "manual",
17
+ "workspace": [
18
+ "./src/lib/kernel",
19
+ "./src/lib/runes/layout",
20
+ "./src/lib/runes/palettes",
21
+ "./src/lib/runes/plugins/money"
22
+ ],
23
+ "tasks": {
24
+ "i18n": "paraglide-js compile --project ./src/lib/i18n/project.inlang --outdir ./src/lib/i18n/paraglide"
25
+ },
26
+ "imports": {
27
+ "@rune-lab/core": "./src/lib/mod.ts",
28
+ "@rune-lab/i18n/": "./src/lib/i18n/",
29
+ "typescript": "npm:typescript@5.9.3",
30
+ "@tailwindcss/vite": "npm:@tailwindcss/vite",
31
+ "esm-env": "npm:esm-env",
32
+ "vite": "npm:vite",
33
+ "vite-plus": "npm:vite-plus",
34
+ "daisyui/": "npm:daisyui/",
35
+ "hotkeys-js": "npm:hotkeys-js",
36
+ "@inlang/paraglide-js": "npm:@inlang/paraglide-js",
37
+ "svelte": "npm:svelte",
38
+ "@sveltejs/kit": "npm:@sveltejs/kit",
39
+ "@sveltejs/vite-plugin-svelte": "npm:@sveltejs/vite-plugin-svelte",
40
+ "@sveltejs/adapter-static": "npm:@sveltejs/adapter-static",
41
+ "jsdom": "npm:jsdom",
42
+ "@testing-library/jest-dom": "npm:@testing-library/jest-dom"
43
+ },
44
+ "exclude": [
45
+ ".*",
46
+ "scripts/**",
47
+ "dist/**",
48
+ "**/*.test.ts"
49
+ ]
13
50
  }
package/justfile ADDED
@@ -0,0 +1,5 @@
1
+ set shell := ["bash", "-cu"]
2
+
3
+ import 'scripts/dev.just'
4
+ import 'scripts/ci.just'
5
+ import 'scripts/deploy.just'
package/package.json CHANGED
@@ -1,25 +1,5 @@
1
1
  {
2
2
  "name": "rune-lab",
3
- "version": "0.4.2-beta.1",
4
- "description": "Modern toolkit for Svelte 5 Runes applications.",
5
- "type": "module",
6
- "exports": {
7
- ".": "./src/mod.ts"
8
- },
9
- "license": "MIT",
10
- "repository": {
11
- "type": "git",
12
- "url": "git+https://github.com/Yrrrrrf/rune-lab.git"
13
- },
14
- "peerDependencies": {
15
- "svelte": "^5.0.0",
16
- "@inlang/paraglide-js": "^2.0.0"
17
- },
18
- "keywords": [
19
- "svelte",
20
- "svelte-5",
21
- "runes",
22
- "ui",
23
- "components"
24
- ]
3
+ "version": "0.4.2-beta.2",
4
+ "packageManager": "pnpm@10.33.0"
25
5
  }
@@ -0,0 +1,57 @@
1
+ // scripts/build_pkg.ts
2
+ import denoConfig from "../deno.json" with { type: "json" };
3
+
4
+ // ── 1. Restructure: move dist/* → dist/src/ ──────────────────────────────────
5
+ await Deno.mkdir("./dist/src", { recursive: true });
6
+ for await (const entry of Deno.readDir("./dist")) {
7
+ if (entry.name === "src") continue;
8
+ await Deno.rename(`./dist/${entry.name}`, `./dist/src/${entry.name}`);
9
+ }
10
+
11
+ // ── Shared metadata ───────────────────────────────────────────────────────────
12
+ const exports = { ".": "./src/mod.ts" };
13
+ const imports = {
14
+ "esm-env": "npm:esm-env@^1.2.2",
15
+ "hotkeys-js": "npm:hotkeys-js@^4.0.2",
16
+ "dinero.js": "npm:dinero.js@^2.0.2",
17
+ "svelte": "npm:svelte@^5.55.0",
18
+ "svelte/": "npm:svelte@^5.55.0/",
19
+ "@sveltejs/kit": "npm:@sveltejs/kit@^2.55.0",
20
+ "@inlang/paraglide-js": "npm:@inlang/paraglide-js@^2.15.1",
21
+ "@inlang/": "npm:@inlang/paraglide-js@^2.15.1/",
22
+ };
23
+ const peerDependencies = {
24
+ "svelte": "^5.0.0",
25
+ "@inlang/paraglide-js": "^2.0.0",
26
+ };
27
+ const meta = {
28
+ version: denoConfig.version,
29
+ description: denoConfig.description,
30
+ license: denoConfig.license,
31
+ repository: denoConfig.repository,
32
+ };
33
+
34
+ // ── 2. Generate dist/deno.json ────────────────────────────────────────────────
35
+ await Deno.writeTextFile("./dist/deno.json", JSON.stringify({
36
+ name: "@yrrrrrf/rune-lab", // JSR scoped name
37
+ ...meta,
38
+ exports,
39
+ imports,
40
+ }, null, 2));
41
+
42
+ // ── 3. Generate dist/package.json ─────────────────────────────────────────────
43
+ await Deno.writeTextFile("./dist/package.json", JSON.stringify({
44
+ name: "rune-lab", // npm unscoped name
45
+ ...meta,
46
+ type: "module",
47
+ exports,
48
+ imports,
49
+ peerDependencies,
50
+ keywords: ["svelte", "svelte-5", "runes", "ui", "components"],
51
+ }, null, 2));
52
+
53
+ // ── 4. Copy metadata ──────────────────────────────────────────────────────────
54
+ await Deno.copyFile("README.md", "./dist/README.md");
55
+ await Deno.copyFile("LICENSE", "./dist/LICENSE");
56
+
57
+ console.log(`dist/ (v${denoConfig.version})`);
@@ -0,0 +1,26 @@
1
+ [doc('Format Client code')]
2
+ [group('CI')]
3
+ fmt:
4
+ deno fmt .
5
+ @echo "✓ Client code formatted"
6
+
7
+ [doc('Lint Client code')]
8
+ [group('CI')]
9
+ lint:
10
+ deno lint .
11
+ @echo "✓ Client code linted"
12
+
13
+ [doc('Type-check Client workspace')]
14
+ [group('CI')]
15
+ typecheck:
16
+ # check ts types with strict deno.ns
17
+ deno check .
18
+ # check svelte types
19
+ deno run -A npm:svelte-check
20
+ # todo: Maybe change this to a vp command
21
+ @echo "✓ Client type-checked"
22
+
23
+ [doc('Full client quality gate')]
24
+ [group('CI')]
25
+ quality: fmt lint typecheck
26
+ @echo "✓ Client quality checks passed"
@@ -0,0 +1,26 @@
1
+ [doc('Build Client')]
2
+ [group('Build')]
3
+ build:
4
+ # * Clean up previous build
5
+ rm -rf dist/
6
+ # * Build library using vite-plus
7
+ deno run -A npm:@sveltejs/package -- -i src -o dist
8
+ # vp build
9
+ # * Build ESM package
10
+ # deno run -A scripts/build_pkg.ts
11
+ @echo "✓ build done"
12
+
13
+ [doc('Publish to jsr')]
14
+ [group('Deploy')]
15
+ deploy: build
16
+ # * Format build output
17
+ # deno fmt --no-config dist
18
+ deno fmt dist
19
+ # * Publish to npm
20
+ # (cd dist && bun publish)
21
+ # * Publish to jsr
22
+ # rm -rf /tmp/rune-lab
23
+ # cp -r dist/ /tmp/rune-lab
24
+ # (cd /tmp/rune-lab && deno publish --no-check)
25
+ # (cd /tmp/rune-lab && deno install && deno publish --no-check --allow-slow-types)
26
+ @echo "✓ deploy done"
@@ -0,0 +1,4 @@
1
+ [doc('Test the client (runs once)')]
2
+ [group('Dev')]
3
+ test *args:
4
+ vp test
@@ -0,0 +1,72 @@
1
+ # inject.just — surgical local rune-lab injection
2
+ #
3
+ # ⚠ IMPORTANT: `just -f` changes cwd to the justfile's directory.
4
+ # Never pass `.` as dest — pass $PWD or an absolute path instead.
5
+ #
6
+ # Usage:
7
+ # just -f ~/rune-lab/scripts/inject.just inject $PWD
8
+ # just -f ~/rune-lab/scripts/inject.just inject /absolute/path/to/project
9
+ # just -f ~/rune-lab/scripts/inject.just inject-clean $PWD
10
+ #
11
+ # Recipes:
12
+ # inject — build rune-lab, then hot-swap node_modules/rune-lab
13
+ # inject-clean — full dep reset (yog reborn --deep), then inject
14
+ # ─────────────────────────────────────────────────────────────────────────────
15
+
16
+ # Hot-swap: rebuild rune-lab and inject into <dest>/node_modules/rune-lab
17
+ inject dest: _build-for-inject
18
+ #!/usr/bin/env bash
19
+ set -euo pipefail
20
+
21
+ dest_abs="{{ dest }}"
22
+
23
+ # Reject relative paths — they resolve to rune-lab's own dir, not the caller's
24
+ if [[ "$dest_abs" != /* ]]; then
25
+ echo "❌ dest must be an absolute path."
26
+ echo " Call with: just -f ... inject \$PWD"
27
+ echo " Got: $dest_abs"
28
+ exit 1
29
+ fi
30
+
31
+ if [ ! -d "$dest_abs/node_modules" ]; then
32
+ echo "❌ No node_modules/ found in $dest_abs"
33
+ echo " Run your package manager's install first, then retry."
34
+ exit 1
35
+ fi
36
+
37
+ echo "🗑 Removing stale $dest_abs/node_modules/rune-lab..."
38
+ rm -rf "$dest_abs/node_modules/rune-lab"
39
+
40
+ echo "📦 Copying local dist into $dest_abs/node_modules/rune-lab..."
41
+ mkdir -p "$dest_abs/node_modules/rune-lab"
42
+ cp -r "{{ justfile_directory() }}/../dist" "$dest_abs/node_modules/rune-lab/dist"
43
+ cp "{{ justfile_directory() }}/../package.json" "$dest_abs/node_modules/rune-lab/package.json"
44
+
45
+ echo "✅ Done! node_modules/rune-lab → $(du -sh $dest_abs/node_modules/rune-lab | cut -f1)"
46
+ echo " Source: {{ justfile_directory() }}/../dist"
47
+ echo " Target: $dest_abs/node_modules/rune-lab"
48
+
49
+ # Full reset: nuke deps in <dest>, reinstall, then hot-swap rune-lab
50
+ inject-clean dest: _build-for-inject
51
+ #!/usr/bin/env bash
52
+ set -euo pipefail
53
+
54
+ dest_abs="{{ dest }}"
55
+
56
+ if [[ "$dest_abs" != /* ]]; then
57
+ echo "❌ dest must be an absolute path. Call with: just -f ... inject-clean \$PWD"
58
+ exit 1
59
+ fi
60
+
61
+ echo "💀 Running yog reborn --deep in $dest_abs..."
62
+ (cd "$dest_abs" && yog reborn --deep)
63
+
64
+ just -f "{{ justfile_directory() }}/inject.just" inject "$dest_abs"
65
+
66
+ # ── Internal ──────────────────────────────────────────────────────────────────
67
+
68
+ [private]
69
+ _build-for-inject:
70
+ @echo "🔨 Building rune-lab from {{ justfile_directory() }}/.."
71
+ just --justfile "{{ justfile_directory() }}/../justfile" --working-directory "{{ justfile_directory() }}/.." build
72
+ @echo "✅ rune-lab built."
package/src/app.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ // See https://svelte.dev/docs/kit/types#app.d.ts
2
+ // for information about these interfaces
3
+ declare global {
4
+ namespace App {
5
+ // interface Error {}
6
+ // interface Locals {}
7
+ // interface PageData {}
8
+ // interface PageState {}
9
+ // interface Platform {}
10
+ }
11
+ }
12
+
13
+ export {};
package/src/app.html ADDED
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <link rel="icon" href="%sveltekit.assets%/favicon.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
7
+ %sveltekit.head%
8
+ </head>
9
+ <body data-sveltekit-preload-data="hover">
10
+ <div style="display: contents">%sveltekit.body%</div>
11
+ </body>
12
+ </html>
@@ -0,0 +1,105 @@
1
+ <script lang="ts">
2
+ import { setContext, untrack, type Snippet, onMount, type Component } from "svelte";
3
+ import {
4
+ RUNE_LAB_CONTEXT,
5
+ localStorageDriver,
6
+ initializeStores,
7
+ defineRune,
8
+ } from "@rune-lab/kernel";
9
+ import type { PersistenceDriver, RunePlugin } from "@rune-lab/kernel";
10
+
11
+ /**
12
+ * Namespaced configuration for Rune Lab plugins.
13
+ * Keyed by plugin.id.
14
+ */
15
+ export interface RuneLabConfig {
16
+ persistence?: PersistenceDriver;
17
+ /** Optional head management properties */
18
+ favicon?: string;
19
+ manageHead?: boolean;
20
+ icons?: "material" | "none";
21
+ /** Namespaced config for plugins */
22
+ [pluginId: string]: unknown;
23
+ }
24
+
25
+ let { children, config = {}, plugins = [] } = $props<{
26
+ children: Snippet;
27
+ config?: RuneLabConfig;
28
+ plugins?: RunePlugin[];
29
+ }>();
30
+
31
+ const initialPlugins = untrack(() => plugins);
32
+ const initialPersistence = untrack(() => config.persistence ?? localStorageDriver);
33
+
34
+ // 1. Register all plugins
35
+ // Note: defineRune maps each slot into the STORE_REGISTRY
36
+ untrack(() => {
37
+ for (const plugin of initialPlugins) {
38
+ defineRune(plugin);
39
+ }
40
+ });
41
+
42
+ // 2. Initialize all stores via the registry's topological sort
43
+ const stores = initializeStores(
44
+ initialPlugins,
45
+ untrack(() => config as Record<string, unknown>),
46
+ initialPersistence
47
+ );
48
+
49
+ // 3. Provide all stores as context
50
+ // We iterate ALL registered plugins to find the context keys for their slots
51
+ for (const plugin of initialPlugins) {
52
+ for (const slot of plugin.stores) {
53
+ const store = stores.get(slot.id);
54
+ if (store) {
55
+ setContext(slot.contextKey, store);
56
+ }
57
+ }
58
+ }
59
+
60
+ // Also provide the persistence driver itself
61
+ setContext(RUNE_LAB_CONTEXT.persistence, initialPersistence);
62
+
63
+ // 4. Collect all overlays
64
+ const allOverlays = $derived(plugins.flatMap(p => p.overlays ?? []) as Component<Record<never, never>>[]);
65
+
66
+ // ── Initialization for layout ──────────────────────────
67
+ const appStore = stores.get("app") as any;
68
+ const layoutStore = stores.get("layout") as any;
69
+
70
+ onMount(() => {
71
+ if (layoutStore) layoutStore.init();
72
+ });
73
+
74
+ // Meta tags derived from app store state
75
+ const metaTags = $derived(appStore ? [
76
+ { name: "description", content: appStore.description },
77
+ { name: "author", content: appStore.author },
78
+ ] : []);
79
+ </script>
80
+
81
+ <svelte:head>
82
+ {#if config.manageHead !== false && appStore}
83
+ <title>{appStore.name}</title>
84
+ {#if config.favicon}
85
+ <link rel="icon" href={config.favicon} />
86
+ {/if}
87
+ {#each metaTags as meta}
88
+ <meta name={meta.name} content={meta.content} />
89
+ {/each}
90
+ {#if config.icons === "material"}
91
+ <link
92
+ rel="stylesheet"
93
+ href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200"
94
+ />
95
+ {/if}
96
+ {/if}
97
+ </svelte:head>
98
+
99
+ <!-- Plugin Overlays -->
100
+ {#each allOverlays as Overlay}
101
+ <Overlay />
102
+ {/each}
103
+
104
+ <!-- Render Children -->
105
+ {@render children()}
@@ -0,0 +1,103 @@
1
+ import { describe, expect, it, vi } from "vite-plus/test";
2
+
3
+ // Mock esm-env before importing the module
4
+ vi.mock("esm-env", () => ({ DEV: true }));
5
+
6
+ import {
7
+ batchResolveMessages,
8
+ createMessageResolver,
9
+ hasMessage,
10
+ } from "./message-resolver.ts";
11
+
12
+ describe("MessageResolver", () => {
13
+ const mockMessages = {
14
+ usd: () => "US Dollar",
15
+ eur: () => "Euro",
16
+ mxn: () => "Mexican Peso",
17
+ jpy: () => "Japanese Yen",
18
+ };
19
+
20
+ describe("createMessageResolver", () => {
21
+ it("should resolve a key via keyExtractor", () => {
22
+ const resolver = createMessageResolver<{ code: string }>(mockMessages, {
23
+ keyExtractor: (opt) => opt.code,
24
+ keyTransformer: (key) => key.toLowerCase(),
25
+ });
26
+
27
+ expect(resolver({ code: "USD" })).toBe("US Dollar");
28
+ expect(resolver({ code: "EUR" })).toBe("Euro");
29
+ });
30
+
31
+ it("should use untransformed key when no transformer provided", () => {
32
+ const resolver = createMessageResolver<{ code: string }>(mockMessages, {
33
+ keyExtractor: (opt) => opt.code,
34
+ });
35
+
36
+ // Without transformer, keys must match exactly
37
+ expect(resolver({ code: "usd" })).toBe("US Dollar");
38
+ });
39
+
40
+ it("should fall back to the raw key for missing translations", () => {
41
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
42
+
43
+ const resolver = createMessageResolver<{ code: string }>(mockMessages, {
44
+ keyExtractor: (opt) => opt.code,
45
+ keyTransformer: (key) => key.toLowerCase(),
46
+ });
47
+
48
+ const result = resolver({ code: "UNKNOWN" });
49
+ expect(result).toBe("UNKNOWN"); // falls back to original key
50
+ expect(warnSpy).toHaveBeenCalledWith(
51
+ expect.stringContaining("Missing translation"),
52
+ );
53
+
54
+ warnSpy.mockRestore();
55
+ });
56
+ });
57
+
58
+ describe("hasMessage", () => {
59
+ it("should return true for existing keys", () => {
60
+ expect(hasMessage(mockMessages, "usd")).toBe(true);
61
+ expect(hasMessage(mockMessages, "eur")).toBe(true);
62
+ });
63
+
64
+ it("should return false for missing keys", () => {
65
+ expect(hasMessage(mockMessages, "UNKNOWN")).toBe(false);
66
+ expect(hasMessage(mockMessages, "")).toBe(false);
67
+ });
68
+ });
69
+
70
+ describe("batchResolveMessages", () => {
71
+ it("should resolve all options at once", () => {
72
+ const options = [{ code: "USD" }, { code: "EUR" }, { code: "MXN" }];
73
+
74
+ const result = batchResolveMessages(mockMessages, options, {
75
+ keyExtractor: (opt) => opt.code,
76
+ keyTransformer: (key) => key.toLowerCase(),
77
+ });
78
+
79
+ expect(result).toEqual({
80
+ USD: "US Dollar",
81
+ EUR: "Euro",
82
+ MXN: "Mexican Peso",
83
+ });
84
+ });
85
+
86
+ it("should include fallback values for missing keys", () => {
87
+ vi.spyOn(console, "warn").mockImplementation(() => {});
88
+
89
+ const options = [{ code: "USD" }, { code: "XYZ" }];
90
+ const result = batchResolveMessages(mockMessages, options, {
91
+ keyExtractor: (opt) => opt.code,
92
+ keyTransformer: (key) => key.toLowerCase(),
93
+ });
94
+
95
+ expect(result).toEqual({
96
+ USD: "US Dollar",
97
+ XYZ: "XYZ", // fallback
98
+ });
99
+
100
+ vi.restoreAllMocks();
101
+ });
102
+ });
103
+ });
@@ -0,0 +1,89 @@
1
+ // sdk/devtools/src/patterns/message-resolver.ts
2
+ import { DEV } from "esm-env";
3
+
4
+ /**
5
+ * Dynamic i18n Message Resolver Pattern
6
+ *
7
+ * Enables dynamic message function calls for config selectors.
8
+ * Creates a resolver that dynamically looks up and calls message functions.
9
+ */
10
+
11
+ type MessageBundle = Record<string, (...args: unknown[]) => string>;
12
+
13
+ interface MessageResolverConfig<T> {
14
+ /**
15
+ * Function to extract the message key from an option
16
+ * @example (currency) => currency.code // "USD"
17
+ */
18
+ keyExtractor: (option: T) => string;
19
+
20
+ /**
21
+ * Optional transformer for the key before message lookup
22
+ * @example (key) => key.toLowerCase() // "USD" -> "usd"
23
+ */
24
+ keyTransformer?: (key: string) => string;
25
+ }
26
+
27
+ /**
28
+ * Creates a message resolver function for dynamic i18n lookups
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * const getCurrencyLabel = createMessageResolver<Currency>(m, {
33
+ * keyExtractor: (currency) => currency.code
34
+ * });
35
+ *
36
+ * getCurrencyLabel({ code: "EUR", symbol: "€" }); // "Euro"
37
+ * ```
38
+ */
39
+ export function createMessageResolver<T>(
40
+ messages: MessageBundle,
41
+ config: MessageResolverConfig<T>,
42
+ ) {
43
+ return (option: T): string => {
44
+ const key = config.keyExtractor(option);
45
+ const transformedKey = config.keyTransformer
46
+ ? config.keyTransformer(key)
47
+ : key;
48
+
49
+ const messageFn = messages[transformedKey];
50
+
51
+ if (!messageFn || typeof messageFn !== "function") {
52
+ if (DEV) {
53
+ console.warn(
54
+ `[MessageResolver] Missing translation for key: "${transformedKey}"`,
55
+ );
56
+ }
57
+ return key; // Fallback to key
58
+ }
59
+
60
+ return messageFn();
61
+ };
62
+ }
63
+
64
+ /**
65
+ * Type guard to check if a message key exists
66
+ */
67
+ export function hasMessage(messages: MessageBundle, key: string): boolean {
68
+ return key in messages && typeof messages[key] === "function";
69
+ }
70
+
71
+ /**
72
+ * Batch resolver for multiple options at once
73
+ */
74
+ export function batchResolveMessages<T>(
75
+ messages: MessageBundle,
76
+ options: T[],
77
+ config: MessageResolverConfig<T>,
78
+ ): Record<string, string> {
79
+ const resolver = createMessageResolver(messages, config);
80
+
81
+ return options.reduce(
82
+ (acc, option) => {
83
+ const key = config.keyExtractor(option);
84
+ acc[key] = resolver(option);
85
+ return acc;
86
+ },
87
+ {} as Record<string, string>,
88
+ );
89
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "$schema": "https://inlang.com/schema/project-settings",
3
+ "baseLocale": "en",
4
+ "locales": [
5
+ "es",
6
+ "fr",
7
+ "it",
8
+ "pt",
9
+ "en",
10
+ "de",
11
+ "ru",
12
+ "hi",
13
+ "ar",
14
+ "zh",
15
+ "ja",
16
+ "ko",
17
+ "vi"
18
+ ],
19
+ "modules": [
20
+ "https://cdn.jsdelivr.net/npm/@inlang/plugin-message-format@4/dist/index.js",
21
+ "https://cdn.jsdelivr.net/npm/@inlang/plugin-m-function-matcher@2/dist/index.js"
22
+ ],
23
+ "plugin.inlang.messageFormat": {
24
+ "pathPattern": "./translations/{locale}.json"
25
+ }
26
+ }