@gtkx/cli 0.21.0 → 1.0.0-rc.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 (358) hide show
  1. package/README.md +173 -0
  2. package/bin/gtkx-dev-runner.js +9 -0
  3. package/dist/builder.d.ts +5 -52
  4. package/dist/builder.d.ts.map +1 -1
  5. package/dist/builder.js +24 -57
  6. package/dist/builder.js.map +1 -1
  7. package/dist/cli.d.ts +1 -2
  8. package/dist/cli.d.ts.map +1 -1
  9. package/dist/cli.js +24 -122
  10. package/dist/cli.js.map +1 -1
  11. package/dist/codegen/freshness.d.ts +11 -0
  12. package/dist/codegen/freshness.d.ts.map +1 -0
  13. package/dist/codegen/freshness.js +45 -0
  14. package/dist/codegen/freshness.js.map +1 -0
  15. package/dist/codegen/report.d.ts +4 -0
  16. package/dist/codegen/report.d.ts.map +1 -0
  17. package/dist/codegen/report.js +18 -0
  18. package/dist/codegen/report.js.map +1 -0
  19. package/dist/codegen/run-codegen.d.ts +35 -0
  20. package/dist/codegen/run-codegen.d.ts.map +1 -0
  21. package/dist/codegen/run-codegen.js +162 -0
  22. package/dist/codegen/run-codegen.js.map +1 -0
  23. package/dist/codegen/store-resolver.d.ts +24 -0
  24. package/dist/codegen/store-resolver.d.ts.map +1 -0
  25. package/dist/codegen/store-resolver.js +72 -0
  26. package/dist/codegen/store-resolver.js.map +1 -0
  27. package/dist/commands/build.d.ts +10 -0
  28. package/dist/commands/build.d.ts.map +1 -0
  29. package/dist/commands/build.js +34 -0
  30. package/dist/commands/build.js.map +1 -0
  31. package/dist/commands/codegen.d.ts +10 -0
  32. package/dist/commands/codegen.d.ts.map +1 -0
  33. package/dist/commands/codegen.js +42 -0
  34. package/dist/commands/codegen.js.map +1 -0
  35. package/dist/commands/dev.d.ts +6 -0
  36. package/dist/commands/dev.d.ts.map +1 -0
  37. package/dist/commands/dev.js +22 -0
  38. package/dist/commands/dev.js.map +1 -0
  39. package/dist/commands/docs.d.ts +20 -0
  40. package/dist/commands/docs.d.ts.map +1 -0
  41. package/dist/commands/docs.js +74 -0
  42. package/dist/commands/docs.js.map +1 -0
  43. package/dist/dev/icon-dir.d.ts +3 -0
  44. package/dist/dev/icon-dir.d.ts.map +1 -0
  45. package/dist/dev/icon-dir.js +16 -0
  46. package/dist/dev/icon-dir.js.map +1 -0
  47. package/dist/dev/refresh-tracker.d.ts +7 -0
  48. package/dist/dev/refresh-tracker.d.ts.map +1 -0
  49. package/dist/dev/refresh-tracker.js +19 -0
  50. package/dist/dev/refresh-tracker.js.map +1 -0
  51. package/dist/dev/runner-deps.d.ts +4 -0
  52. package/dist/dev/runner-deps.d.ts.map +1 -0
  53. package/dist/dev/runner-deps.js +55 -0
  54. package/dist/dev/runner-deps.js.map +1 -0
  55. package/dist/dev/runner-main.d.ts +3 -0
  56. package/dist/dev/runner-main.d.ts.map +1 -0
  57. package/dist/dev/runner-main.js +29 -0
  58. package/dist/dev/runner-main.js.map +1 -0
  59. package/dist/dev/runner.d.ts +24 -0
  60. package/dist/dev/runner.d.ts.map +1 -0
  61. package/dist/dev/runner.js +119 -0
  62. package/dist/dev/runner.js.map +1 -0
  63. package/dist/dev/schema-dir.d.ts +3 -0
  64. package/dist/dev/schema-dir.d.ts.map +1 -0
  65. package/dist/dev/schema-dir.js +12 -0
  66. package/dist/dev/schema-dir.js.map +1 -0
  67. package/dist/dev/supervisor.d.ts +18 -0
  68. package/dist/dev/supervisor.d.ts.map +1 -0
  69. package/dist/dev/supervisor.js +182 -0
  70. package/dist/dev/supervisor.js.map +1 -0
  71. package/dist/dev/vite-dev-server.d.ts +21 -0
  72. package/dist/dev/vite-dev-server.d.ts.map +1 -0
  73. package/dist/dev/vite-dev-server.js +13 -0
  74. package/dist/dev/vite-dev-server.js.map +1 -0
  75. package/dist/internal/banner.d.ts +4 -0
  76. package/dist/internal/banner.d.ts.map +1 -0
  77. package/dist/internal/banner.js +9 -0
  78. package/dist/internal/banner.js.map +1 -0
  79. package/dist/internal/data-dir.d.ts +4 -0
  80. package/dist/internal/data-dir.d.ts.map +1 -0
  81. package/dist/internal/data-dir.js +52 -0
  82. package/dist/internal/data-dir.js.map +1 -0
  83. package/dist/internal/entry-arg.d.ts +20 -0
  84. package/dist/internal/entry-arg.d.ts.map +1 -0
  85. package/dist/internal/entry-arg.js +36 -0
  86. package/dist/internal/entry-arg.js.map +1 -0
  87. package/dist/internal/errors.d.ts +5 -0
  88. package/dist/internal/errors.d.ts.map +1 -0
  89. package/dist/internal/errors.js +29 -0
  90. package/dist/internal/errors.js.map +1 -0
  91. package/dist/internal/list-files.d.ts +7 -0
  92. package/dist/internal/list-files.d.ts.map +1 -0
  93. package/dist/internal/list-files.js +15 -0
  94. package/dist/internal/list-files.js.map +1 -0
  95. package/dist/internal/resolve-cli-tool.d.ts +3 -0
  96. package/dist/internal/resolve-cli-tool.d.ts.map +1 -0
  97. package/dist/internal/resolve-cli-tool.js +27 -0
  98. package/dist/internal/resolve-cli-tool.js.map +1 -0
  99. package/dist/internal/staging-dir.d.ts +4 -0
  100. package/dist/internal/staging-dir.d.ts.map +1 -0
  101. package/dist/internal/staging-dir.js +17 -0
  102. package/dist/internal/staging-dir.js.map +1 -0
  103. package/dist/internal/xdg-data-dirs.d.ts +3 -0
  104. package/dist/internal/xdg-data-dirs.d.ts.map +1 -0
  105. package/dist/internal/xdg-data-dirs.js +10 -0
  106. package/dist/internal/xdg-data-dirs.js.map +1 -0
  107. package/dist/mcp/client.d.ts +28 -0
  108. package/dist/mcp/client.d.ts.map +1 -0
  109. package/dist/mcp/client.js +182 -0
  110. package/dist/mcp/client.js.map +1 -0
  111. package/dist/mcp/handlers.d.ts +9 -0
  112. package/dist/mcp/handlers.d.ts.map +1 -0
  113. package/dist/mcp/handlers.js +147 -0
  114. package/dist/mcp/handlers.js.map +1 -0
  115. package/dist/mcp/index.d.ts +4 -0
  116. package/dist/mcp/index.d.ts.map +1 -0
  117. package/dist/mcp/index.js +34 -0
  118. package/dist/mcp/index.js.map +1 -0
  119. package/dist/mcp/serialize-widget.d.ts +10 -0
  120. package/dist/mcp/serialize-widget.d.ts.map +1 -0
  121. package/dist/mcp/serialize-widget.js +23 -0
  122. package/dist/mcp/serialize-widget.js.map +1 -0
  123. package/dist/mcp/testing-loader.d.ts +5 -0
  124. package/dist/mcp/testing-loader.d.ts.map +1 -0
  125. package/dist/mcp/testing-loader.js +47 -0
  126. package/dist/mcp/testing-loader.js.map +1 -0
  127. package/dist/mcp/widget-registry.d.ts +14 -0
  128. package/dist/mcp/widget-registry.d.ts.map +1 -0
  129. package/dist/mcp/widget-registry.js +39 -0
  130. package/dist/mcp/widget-registry.js.map +1 -0
  131. package/dist/refresh-globals.d.ts +2 -0
  132. package/dist/refresh-globals.d.ts.map +1 -0
  133. package/dist/refresh-globals.js +8 -0
  134. package/dist/refresh-globals.js.map +1 -0
  135. package/dist/refresh-runtime.d.ts +10 -26
  136. package/dist/refresh-runtime.d.ts.map +1 -1
  137. package/dist/refresh-runtime.js +26 -48
  138. package/dist/refresh-runtime.js.map +1 -1
  139. package/dist/settings/compile.d.ts +3 -0
  140. package/dist/settings/compile.d.ts.map +1 -0
  141. package/dist/settings/compile.js +21 -0
  142. package/dist/settings/compile.js.map +1 -0
  143. package/dist/settings/parser.d.ts +24 -0
  144. package/dist/settings/parser.d.ts.map +1 -0
  145. package/dist/settings/parser.js +121 -0
  146. package/dist/settings/parser.js.map +1 -0
  147. package/dist/settings/render.d.ts +5 -0
  148. package/dist/settings/render.d.ts.map +1 -0
  149. package/dist/settings/render.js +122 -0
  150. package/dist/settings/render.js.map +1 -0
  151. package/dist/settings/schema.d.ts +13 -0
  152. package/dist/settings/schema.d.ts.map +1 -0
  153. package/dist/settings/schema.js +121 -0
  154. package/dist/settings/schema.js.map +1 -0
  155. package/dist/vite-plugins/asset-extensions.d.ts +5 -0
  156. package/dist/vite-plugins/asset-extensions.d.ts.map +1 -0
  157. package/dist/vite-plugins/asset-extensions.js +28 -0
  158. package/dist/vite-plugins/asset-extensions.js.map +1 -0
  159. package/dist/vite-plugins/built-url.d.ts +4 -0
  160. package/dist/vite-plugins/built-url.d.ts.map +1 -0
  161. package/dist/vite-plugins/built-url.js +36 -0
  162. package/dist/vite-plugins/built-url.js.map +1 -0
  163. package/dist/vite-plugins/css.d.ts +4 -0
  164. package/dist/vite-plugins/css.d.ts.map +1 -0
  165. package/dist/vite-plugins/css.js +38 -0
  166. package/dist/vite-plugins/css.js.map +1 -0
  167. package/dist/vite-plugins/fast-refresh/refresh-filter.d.ts +8 -0
  168. package/dist/vite-plugins/fast-refresh/refresh-filter.d.ts.map +1 -0
  169. package/dist/vite-plugins/fast-refresh/refresh-filter.js +19 -0
  170. package/dist/vite-plugins/fast-refresh/refresh-filter.js.map +1 -0
  171. package/dist/vite-plugins/fast-refresh/swc-refresh.d.ts +6 -0
  172. package/dist/vite-plugins/fast-refresh/swc-refresh.d.ts.map +1 -0
  173. package/dist/vite-plugins/fast-refresh/swc-refresh.js +70 -0
  174. package/dist/vite-plugins/fast-refresh/swc-refresh.js.map +1 -0
  175. package/dist/vite-plugins/icons.d.ts +4 -0
  176. package/dist/vite-plugins/icons.d.ts.map +1 -0
  177. package/dist/vite-plugins/icons.js +51 -0
  178. package/dist/vite-plugins/icons.js.map +1 -0
  179. package/dist/vite-plugins/index.d.ts +4 -0
  180. package/dist/vite-plugins/index.d.ts.map +1 -0
  181. package/dist/vite-plugins/index.js +22 -0
  182. package/dist/vite-plugins/index.js.map +1 -0
  183. package/dist/vite-plugins/native.d.ts +4 -0
  184. package/dist/vite-plugins/native.d.ts.map +1 -0
  185. package/dist/vite-plugins/native.js +62 -0
  186. package/dist/vite-plugins/native.js.map +1 -0
  187. package/dist/vite-plugins/react-compiler.d.ts +5 -0
  188. package/dist/vite-plugins/react-compiler.d.ts.map +1 -0
  189. package/dist/vite-plugins/react-compiler.js +62 -0
  190. package/dist/vite-plugins/react-compiler.js.map +1 -0
  191. package/dist/vite-plugins/react-dom-prebundle.d.ts +4 -0
  192. package/dist/vite-plugins/react-dom-prebundle.d.ts.map +1 -0
  193. package/dist/vite-plugins/react-dom-prebundle.js +12 -0
  194. package/dist/vite-plugins/react-dom-prebundle.js.map +1 -0
  195. package/dist/vite-plugins/resource-init-module.d.ts +6 -0
  196. package/dist/vite-plugins/resource-init-module.d.ts.map +1 -0
  197. package/dist/vite-plugins/resource-init-module.js +51 -0
  198. package/dist/vite-plugins/resource-init-module.js.map +1 -0
  199. package/dist/vite-plugins/resource-shared.d.ts +8 -0
  200. package/dist/vite-plugins/resource-shared.d.ts.map +1 -0
  201. package/dist/vite-plugins/resource-shared.js +28 -0
  202. package/dist/vite-plugins/resource-shared.js.map +1 -0
  203. package/dist/vite-plugins/resources.d.ts +5 -0
  204. package/dist/vite-plugins/resources.d.ts.map +1 -0
  205. package/dist/vite-plugins/resources.js +260 -0
  206. package/dist/vite-plugins/resources.js.map +1 -0
  207. package/dist/vite-plugins/settings-worker-env.d.ts +4 -0
  208. package/dist/vite-plugins/settings-worker-env.d.ts.map +1 -0
  209. package/dist/vite-plugins/settings-worker-env.js +23 -0
  210. package/dist/vite-plugins/settings-worker-env.js.map +1 -0
  211. package/dist/vite-plugins/settings.d.ts +4 -0
  212. package/dist/vite-plugins/settings.d.ts.map +1 -0
  213. package/dist/vite-plugins/settings.js +214 -0
  214. package/dist/vite-plugins/settings.js.map +1 -0
  215. package/dist/vite-plugins/strip-query.d.ts +3 -0
  216. package/dist/vite-plugins/strip-query.d.ts.map +1 -0
  217. package/dist/vite-plugins/strip-query.js +6 -0
  218. package/dist/vite-plugins/strip-query.js.map +1 -0
  219. package/dist/vite-plugins/undeclared-library.d.ts +4 -0
  220. package/dist/vite-plugins/undeclared-library.d.ts.map +1 -0
  221. package/dist/vite-plugins/undeclared-library.js +50 -0
  222. package/dist/vite-plugins/undeclared-library.js.map +1 -0
  223. package/dist/vite-plugins/virtual-module.d.ts +22 -0
  224. package/dist/vite-plugins/virtual-module.d.ts.map +1 -0
  225. package/dist/vite-plugins/virtual-module.js +20 -0
  226. package/dist/vite-plugins/virtual-module.js.map +1 -0
  227. package/dist/vitest-plugin.d.ts +10 -0
  228. package/dist/vitest-plugin.d.ts.map +1 -0
  229. package/dist/vitest-plugin.js +12 -0
  230. package/dist/vitest-plugin.js.map +1 -0
  231. package/env.d.ts +91 -8
  232. package/package.json +30 -38
  233. package/src/babel-modules.d.ts +11 -0
  234. package/src/builder.ts +31 -86
  235. package/src/cli.ts +42 -0
  236. package/src/codegen/freshness.ts +65 -0
  237. package/src/codegen/report.ts +28 -0
  238. package/src/codegen/run-codegen.ts +260 -0
  239. package/src/codegen/store-resolver.ts +116 -0
  240. package/src/commands/build.ts +38 -0
  241. package/src/commands/codegen.ts +49 -0
  242. package/src/commands/dev.ts +24 -0
  243. package/src/commands/docs.ts +95 -0
  244. package/src/dev/icon-dir.ts +21 -0
  245. package/src/dev/refresh-tracker.ts +25 -0
  246. package/src/dev/runner-deps.ts +65 -0
  247. package/src/dev/runner-main.ts +34 -0
  248. package/src/dev/runner.ts +185 -0
  249. package/src/dev/schema-dir.ts +16 -0
  250. package/src/dev/supervisor.ts +276 -0
  251. package/src/dev/vite-dev-server.ts +36 -0
  252. package/src/internal/banner.ts +13 -0
  253. package/src/internal/data-dir.ts +70 -0
  254. package/src/internal/entry-arg.ts +46 -0
  255. package/src/internal/errors.ts +36 -0
  256. package/src/internal/list-files.ts +23 -0
  257. package/src/internal/resolve-cli-tool.ts +37 -0
  258. package/src/internal/staging-dir.ts +19 -0
  259. package/src/internal/xdg-data-dirs.ts +13 -0
  260. package/src/mcp/client.ts +235 -0
  261. package/src/mcp/handlers.ts +213 -0
  262. package/src/mcp/index.ts +46 -0
  263. package/src/mcp/serialize-widget.ts +41 -0
  264. package/src/mcp/testing-loader.ts +73 -0
  265. package/src/mcp/widget-registry.ts +49 -0
  266. package/src/refresh-globals.ts +10 -0
  267. package/src/refresh-runtime.ts +30 -55
  268. package/src/settings/compile.ts +22 -0
  269. package/src/settings/parser.ts +193 -0
  270. package/src/settings/render.ts +167 -0
  271. package/src/settings/schema.ts +169 -0
  272. package/src/vite-plugins/asset-extensions.ts +29 -0
  273. package/src/vite-plugins/built-url.ts +50 -0
  274. package/src/vite-plugins/css.ts +53 -0
  275. package/src/vite-plugins/fast-refresh/refresh-filter.ts +26 -0
  276. package/src/vite-plugins/fast-refresh/swc-refresh.ts +92 -0
  277. package/src/vite-plugins/icons.ts +74 -0
  278. package/src/vite-plugins/index.ts +25 -0
  279. package/src/vite-plugins/native.ts +83 -0
  280. package/src/vite-plugins/react-compiler.ts +84 -0
  281. package/src/vite-plugins/react-dom-prebundle.ts +17 -0
  282. package/src/vite-plugins/resource-init-module.ts +57 -0
  283. package/src/vite-plugins/resource-shared.ts +40 -0
  284. package/src/vite-plugins/resources.ts +366 -0
  285. package/src/vite-plugins/settings-worker-env.ts +30 -0
  286. package/src/vite-plugins/settings.ts +286 -0
  287. package/src/vite-plugins/strip-query.ts +7 -0
  288. package/src/vite-plugins/undeclared-library.ts +78 -0
  289. package/src/vite-plugins/virtual-module.ts +44 -0
  290. package/src/vitest-plugin.ts +13 -0
  291. package/dist/create.d.ts +0 -55
  292. package/dist/create.d.ts.map +0 -1
  293. package/dist/create.js +0 -236
  294. package/dist/create.js.map +0 -1
  295. package/dist/dev-server.d.ts +0 -37
  296. package/dist/dev-server.d.ts.map +0 -1
  297. package/dist/dev-server.js +0 -130
  298. package/dist/dev-server.js.map +0 -1
  299. package/dist/index.d.ts +0 -4
  300. package/dist/index.d.ts.map +0 -1
  301. package/dist/index.js +0 -4
  302. package/dist/index.js.map +0 -1
  303. package/dist/mcp-client.d.ts +0 -31
  304. package/dist/mcp-client.d.ts.map +0 -1
  305. package/dist/mcp-client.js +0 -430
  306. package/dist/mcp-client.js.map +0 -1
  307. package/dist/templates.d.ts +0 -9
  308. package/dist/templates.d.ts.map +0 -1
  309. package/dist/templates.js +0 -16
  310. package/dist/templates.js.map +0 -1
  311. package/dist/vite-plugin-gtkx-assets.d.ts +0 -20
  312. package/dist/vite-plugin-gtkx-assets.d.ts.map +0 -1
  313. package/dist/vite-plugin-gtkx-assets.js +0 -57
  314. package/dist/vite-plugin-gtkx-assets.js.map +0 -1
  315. package/dist/vite-plugin-gtkx-built-url.d.ts +0 -18
  316. package/dist/vite-plugin-gtkx-built-url.d.ts.map +0 -1
  317. package/dist/vite-plugin-gtkx-built-url.js +0 -43
  318. package/dist/vite-plugin-gtkx-built-url.js.map +0 -1
  319. package/dist/vite-plugin-gtkx-gsettings.d.ts +0 -28
  320. package/dist/vite-plugin-gtkx-gsettings.d.ts.map +0 -1
  321. package/dist/vite-plugin-gtkx-gsettings.js +0 -147
  322. package/dist/vite-plugin-gtkx-gsettings.js.map +0 -1
  323. package/dist/vite-plugin-gtkx-native.d.ts +0 -14
  324. package/dist/vite-plugin-gtkx-native.d.ts.map +0 -1
  325. package/dist/vite-plugin-gtkx-native.js +0 -53
  326. package/dist/vite-plugin-gtkx-native.js.map +0 -1
  327. package/dist/vite-plugin-gtkx-refresh.d.ts +0 -8
  328. package/dist/vite-plugin-gtkx-refresh.d.ts.map +0 -1
  329. package/dist/vite-plugin-gtkx-refresh.js +0 -37
  330. package/dist/vite-plugin-gtkx-refresh.js.map +0 -1
  331. package/dist/vite-plugin-swc-ssr-refresh.d.ts +0 -8
  332. package/dist/vite-plugin-swc-ssr-refresh.d.ts.map +0 -1
  333. package/dist/vite-plugin-swc-ssr-refresh.js +0 -46
  334. package/dist/vite-plugin-swc-ssr-refresh.js.map +0 -1
  335. package/src/cli.tsx +0 -154
  336. package/src/create.ts +0 -326
  337. package/src/dev-server.tsx +0 -162
  338. package/src/index.ts +0 -3
  339. package/src/mcp-client.ts +0 -518
  340. package/src/templates.ts +0 -26
  341. package/src/vite-plugin-gtkx-assets.ts +0 -69
  342. package/src/vite-plugin-gtkx-built-url.ts +0 -48
  343. package/src/vite-plugin-gtkx-gsettings.ts +0 -168
  344. package/src/vite-plugin-gtkx-native.ts +0 -64
  345. package/src/vite-plugin-gtkx-refresh.ts +0 -54
  346. package/src/vite-plugin-swc-ssr-refresh.ts +0 -61
  347. package/templates/claude/EXAMPLES.md.ejs +0 -744
  348. package/templates/claude/SKILL.md.ejs +0 -93
  349. package/templates/claude/WIDGETS.md.ejs +0 -820
  350. package/templates/config/vitest.config.ts.ejs +0 -11
  351. package/templates/gitignore.ejs +0 -4
  352. package/templates/package.json.ejs +0 -16
  353. package/templates/src/app.tsx.ejs +0 -32
  354. package/templates/src/dev.tsx.ejs +0 -5
  355. package/templates/src/gtkx-env.d.ts.ejs +0 -1
  356. package/templates/src/index.tsx.ejs +0 -5
  357. package/templates/tests/app.test.tsx.ejs +0 -16
  358. package/templates/tsconfig.json.ejs +0 -14
@@ -0,0 +1,11 @@
1
+ declare module "babel-plugin-react-compiler" {
2
+ import type { PluginTarget } from "@babel/core";
3
+ const plugin: PluginTarget & { default?: PluginTarget };
4
+ export default plugin;
5
+ }
6
+
7
+ declare module "@babel/preset-typescript" {
8
+ import type { PresetTarget } from "@babel/core";
9
+ const preset: PresetTarget & { default?: PresetTarget };
10
+ export default preset;
11
+ }
package/src/builder.ts CHANGED
@@ -1,102 +1,47 @@
1
- import { type InlineConfig, build as viteBuild } from "vite";
2
- import { gtkxAssets } from "./vite-plugin-gtkx-assets.js";
3
- import { gtkxBuiltUrl } from "./vite-plugin-gtkx-built-url.js";
4
- import { gtkxGSettings } from "./vite-plugin-gtkx-gsettings.js";
5
- import { gtkxNative } from "./vite-plugin-gtkx-native.js";
1
+ import { type InlineConfig, mergeConfig, build as viteBuild } from "vite";
2
+ import { gtkxBuiltUrl } from "./vite-plugins/built-url.js";
3
+ import { gtkxVitePlugins } from "./vite-plugins/index.js";
4
+ import { gtkxNative } from "./vite-plugins/native.js";
6
5
 
7
- /**
8
- * Options for building a GTKX application for production.
9
- */
10
- export type BuildOptions = {
11
- /** Path to the entry file (e.g., "src/index.tsx") */
6
+ type BuildOptions = {
12
7
  entry: string;
13
- /**
14
- * Base path for resolving asset imports at runtime, relative to the
15
- * executable directory.
16
- *
17
- * When set, asset imports resolve to
18
- * `path.join(path.dirname(process.execPath), assetBase, filename)`.
19
- * This is useful for FHS-compliant packaging where assets live under
20
- * a `share/` directory rather than next to the binary.
21
- *
22
- * When omitted, assets resolve relative to the bundle via
23
- * `import.meta.url`, which works when assets are co-located with
24
- * the executable (e.g., in `bin/assets/`).
25
- *
26
- * @example
27
- * ```ts
28
- * await build({
29
- * entry: "./src/index.tsx",
30
- * assetBase: "../share/my-app",
31
- * });
32
- * ```
33
- */
34
- assetBase?: string;
35
- /** Additional Vite configuration */
36
- vite?: InlineConfig;
8
+ assetBase?: string | undefined;
9
+ vite?: InlineConfig | undefined;
37
10
  };
38
11
 
39
- /**
40
- * Builds a GTKX application for production using Vite's SSR build mode.
41
- *
42
- * Produces a single minified ESM bundle at `dist/bundle.js` with all
43
- * dependencies inlined. The native `.node` binary is copied into the
44
- * output directory as `gtkx.node`, making the bundle fully self-contained
45
- * with no `node_modules` dependency at runtime.
46
- *
47
- * @param options - Build configuration including entry point and Vite options
48
- *
49
- * @example
50
- * ```ts
51
- * import { build } from "@gtkx/cli";
52
- *
53
- * await build({
54
- * entry: "./src/index.tsx",
55
- * vite: { root: process.cwd() },
56
- * });
57
- * ```
58
- *
59
- * @see {@link BuildOptions} for configuration options
60
- */
61
- export const build = async (options: BuildOptions): Promise<void> => {
12
+ const BUILD_MODE = "production";
13
+
14
+ const buildDefaults: InlineConfig = {
15
+ build: {
16
+ ssrEmitAssets: true,
17
+ outDir: "dist",
18
+ minify: true,
19
+ cssMinify: false,
20
+ },
21
+ define: {
22
+ "process.env.NODE_ENV": JSON.stringify(BUILD_MODE),
23
+ },
24
+ };
25
+
26
+ const build = async (options: BuildOptions): Promise<void> => {
62
27
  const { entry, assetBase, vite: viteConfig } = options;
63
28
  const root = viteConfig?.root ?? process.cwd();
64
29
 
65
- await viteBuild({
66
- ...viteConfig,
67
- plugins: [
68
- ...(viteConfig?.plugins ?? []),
69
- gtkxGSettings(),
70
- gtkxAssets(),
71
- gtkxBuiltUrl(assetBase),
72
- gtkxNative(root),
73
- ],
30
+ const forced: InlineConfig = {
31
+ plugins: [...gtkxVitePlugins(BUILD_MODE), gtkxBuiltUrl(assetBase), gtkxNative(root)],
74
32
  build: {
75
- ...viteConfig?.build,
76
33
  ssr: entry,
77
- ssrEmitAssets: true,
78
34
  assetsInlineLimit: 0,
79
- outDir: viteConfig?.build?.outDir ?? "dist",
80
- minify: true,
81
- cssMinify: false,
82
- rollupOptions: {
83
- ...viteConfig?.build?.rollupOptions,
35
+ rolldownOptions: {
84
36
  output: {
85
- ...((viteConfig?.build?.rollupOptions?.output ?? {}) as Record<string, unknown>),
86
37
  entryFileNames: "bundle.js",
87
38
  },
88
39
  },
89
40
  },
90
- define: {
91
- ...viteConfig?.define,
92
- "process.env.NODE_ENV": JSON.stringify("production"),
93
- },
94
- ssr: {
95
- ...viteConfig?.ssr,
96
- noExternal: true,
97
- },
98
- experimental: {
99
- ...viteConfig?.experimental,
100
- },
101
- });
41
+ };
42
+
43
+ const merged: InlineConfig = mergeConfig(mergeConfig(buildDefaults, viteConfig ?? {}), forced);
44
+ await viteBuild({ ...merged, ssr: { ...merged.ssr, noExternal: true } });
102
45
  };
46
+
47
+ export { build, type BuildOptions };
package/src/cli.ts ADDED
@@ -0,0 +1,42 @@
1
+ import { packageVersion } from "@gtkx/utils";
2
+ import { defineCommand, runMain } from "citty";
3
+ import { withErrorBoundary } from "./internal/errors.js";
4
+
5
+ const version = packageVersion(import.meta.url);
6
+
7
+ const main = defineCommand({
8
+ meta: {
9
+ name: "gtkx",
10
+ version,
11
+ description: "CLI for GTKX: create and develop GTK4 React applications",
12
+ },
13
+ subCommands: {
14
+ dev: async () => {
15
+ const { dev } = await import("./commands/dev.js");
16
+
17
+ return withErrorBoundary(dev);
18
+ },
19
+ build: async () => {
20
+ const { build } = await import("./commands/build.js");
21
+
22
+ return withErrorBoundary(build);
23
+ },
24
+ codegen: async () => {
25
+ const { codegen } = await import("./commands/codegen.js");
26
+
27
+ return withErrorBoundary(codegen);
28
+ },
29
+ docs: async () => {
30
+ const { docs } = await import("./commands/docs.js");
31
+
32
+ return withErrorBoundary(docs);
33
+ },
34
+ create: async () => {
35
+ const { scaffoldCommand } = await import("create-gtkx");
36
+
37
+ return withErrorBoundary(scaffoldCommand);
38
+ },
39
+ },
40
+ });
41
+
42
+ await runMain(main);
@@ -0,0 +1,65 @@
1
+ import type { Config } from "@gtkx/config";
2
+ import { resolveGirPath, resolveLibraries } from "@gtkx/codegen";
3
+ import { existsSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { type CodegenStore, resolveCodegenStore } from "./store-resolver.js";
6
+
7
+ type CodegenInputs = {
8
+ girPath: string[];
9
+ libraries: string[];
10
+ store: CodegenStore;
11
+ };
12
+
13
+ const REACT_GENERATED_MODULES: string[] = ["metadata.js", join("gtk", "gtk.js")];
14
+
15
+ const resolveCodegenInputs = (cwd: string, config: Config): CodegenInputs => {
16
+ const girPath = resolveGirPath(config.girPath);
17
+ const libraries = resolveLibraries(config.libraries, girPath);
18
+ const store = resolveCodegenStore(cwd);
19
+
20
+ return { girPath, libraries, store };
21
+ };
22
+
23
+ const namespaceBarrelPath = (giStoreDir: string, library: string): string => {
24
+ const separator = library.indexOf("-");
25
+ const namespace = (separator === -1 ? library : library.slice(0, separator)).toLowerCase();
26
+
27
+ return join(giStoreDir, namespace, "index.js");
28
+ };
29
+
30
+ const canResolveGiStoreLinks = (giStoreDir: string): boolean =>
31
+ existsSync(join(giStoreDir, "node_modules", "@gtkx", "gi", "package.json"));
32
+
33
+ const isGiStoreStale = (store: CodegenStore, libraries: string[]): boolean => {
34
+ if (!existsSync(store.giLinkDir) || !existsSync(store.giStoreDir)) {
35
+ return true;
36
+ }
37
+
38
+ if (!canResolveGiStoreLinks(store.giStoreDir)) {
39
+ return true;
40
+ }
41
+
42
+ return libraries.some((library) => !existsSync(namespaceBarrelPath(store.giStoreDir, library)));
43
+ };
44
+
45
+ const isReactStoreStale = (store: CodegenStore): boolean => {
46
+ if (store.react === null) {
47
+ return false;
48
+ }
49
+
50
+ if (!existsSync(store.jsxLinkDir)) {
51
+ return true;
52
+ }
53
+
54
+ return REACT_GENERATED_MODULES.some((module) => !existsSync(join(store.jsxStoreDir, module)));
55
+ };
56
+
57
+ const isCodegenStale = (inputs: CodegenInputs): boolean => {
58
+ try {
59
+ return isGiStoreStale(inputs.store, inputs.libraries) || isReactStoreStale(inputs.store);
60
+ } catch {
61
+ return true;
62
+ }
63
+ };
64
+
65
+ export { resolveCodegenInputs, isCodegenStale, type CodegenInputs };
@@ -0,0 +1,28 @@
1
+ import type { RunCodegenResult } from "./run-codegen.js";
2
+
3
+ const PREFIX = "codegen: ";
4
+
5
+ const formatCodegenResult = (result: RunCodegenResult, totalMs: number): string[] => {
6
+ const details: string[] = [];
7
+
8
+ if (result.configFile) {
9
+ details.push(`config=${result.configFile}`);
10
+ }
11
+
12
+ if (result.libraries) {
13
+ details.push(`libraries=${result.libraries.join(", ")}`);
14
+ }
15
+
16
+ if (result.girPath) {
17
+ details.push(`girPath=${result.girPath.join(":")}`);
18
+ }
19
+
20
+ details.push(
21
+ `${String(result.namespaces)} namespaces, ${String(result.intrinsicElements)} intrinsic elements ` +
22
+ `in ${String(result.duration)}ms (total ${String(totalMs)}ms)`,
23
+ );
24
+
25
+ return details.map((detail) => PREFIX + detail);
26
+ };
27
+
28
+ export { formatCodegenResult };
@@ -0,0 +1,260 @@
1
+ import { runCodegen as runCodegenCore } from "@gtkx/codegen";
2
+ import { type Config, loadConfig } from "@gtkx/config";
3
+ import { resolveLazyElements } from "@gtkx/config/internal";
4
+ import { info } from "@gtkx/utils";
5
+ import { rmSync } from "node:fs";
6
+ import { resolve } from "node:path";
7
+ import { resolveDataDir } from "../internal/data-dir.js";
8
+ import { emitSchemaEnv } from "../settings/schema.js";
9
+ import { type CodegenInputs, isCodegenStale, resolveCodegenInputs } from "./freshness.js";
10
+ import { type CodegenStore, resolveCodegenContext } from "./store-resolver.js";
11
+
12
+ type RunCodegenOptions = {
13
+ cwd?: string;
14
+ mode?: string | undefined;
15
+ force?: boolean;
16
+ inputs?: CodegenInputs;
17
+ resolved?: LoadedConfig;
18
+ };
19
+
20
+ type LoadedConfig = {
21
+ config: Config;
22
+ configFile: string | undefined;
23
+ };
24
+
25
+ type RunCodegenResult = {
26
+ regenerated: boolean;
27
+ namespaces: number;
28
+ intrinsicElements: number;
29
+ duration: number;
30
+ girPath?: string[] | undefined;
31
+ configFile?: string | undefined;
32
+ libraries?: string[] | undefined;
33
+ };
34
+
35
+ type CodegenOptionsInput = {
36
+ store: CodegenStore;
37
+ libraries: string[];
38
+ girPath: string[];
39
+ elements: Config["elements"];
40
+ };
41
+
42
+ type PreparedCodegen = CodegenInputs & { force: boolean };
43
+
44
+ type RunOptionsInput = {
45
+ root: string;
46
+ mode: string | undefined;
47
+ inputs: CodegenInputs | null;
48
+ resolved: LoadedConfig;
49
+ };
50
+
51
+ const GIR_PATH_MISSING_MESSAGE =
52
+ "No GIR search paths available. Install gobject-introspection " +
53
+ "(Linux: `sudo dnf install gobject-introspection-devel` or `sudo apt install libgirepository1.0-dev`), " +
54
+ "or set `girPath` in gtkx.config.ts.";
55
+
56
+ const removeSharedStoreShadow = (cwd: string): void => {
57
+ for (const path of [
58
+ resolve(cwd, "node_modules/.gtkx/gi"),
59
+ resolve(cwd, "node_modules/.gtkx/jsx"),
60
+ resolve(cwd, "node_modules/@gtkx/gi"),
61
+ resolve(cwd, "node_modules/@gtkx/jsx"),
62
+ ]) {
63
+ rmSync(path, { recursive: true, force: true });
64
+ }
65
+ };
66
+
67
+ const userModuleExports = (
68
+ elements: Config["elements"],
69
+ key: "component" | "props",
70
+ ): Record<string, { module: string; export: string }> =>
71
+ Object.fromEntries(
72
+ Object.entries(elements?.config ?? {}).flatMap(([type, entry]) => {
73
+ const ref = entry[key];
74
+
75
+ return ref === undefined ? [] : [[type, ref] as const];
76
+ }),
77
+ );
78
+
79
+ const codegenOptions = ({ store, libraries, girPath, elements }: CodegenOptionsInput) => ({
80
+ libraries,
81
+ girPath,
82
+ gi: {
83
+ storeDir: store.giStoreDir,
84
+ linkDir: store.giLinkDir,
85
+ version: store.runtimeVersion,
86
+ },
87
+ jsx:
88
+ store.react === null
89
+ ? undefined
90
+ : {
91
+ storeDir: store.jsxStoreDir,
92
+ linkDir: store.jsxLinkDir,
93
+ version: store.react.version,
94
+ },
95
+ reactSubexports: store.react?.subexports ?? [],
96
+ userComponents: userModuleExports(elements, "component"),
97
+ userProps: userModuleExports(elements, "props"),
98
+ userLazyElements: resolveLazyElements(elements),
99
+ });
100
+
101
+ const disabledCodegenResult = (configFile: string | undefined): RunCodegenResult => ({
102
+ regenerated: false,
103
+ namespaces: 0,
104
+ intrinsicElements: 0,
105
+ duration: 0,
106
+ girPath: [],
107
+ configFile,
108
+ libraries: [],
109
+ });
110
+
111
+ const clearGeneratedStores = (store: CodegenStore): void => {
112
+ for (const path of [store.giStoreDir, store.giLinkDir, store.jsxStoreDir, store.jsxLinkDir]) {
113
+ rmSync(path, { recursive: true, force: true });
114
+ }
115
+ };
116
+
117
+ const resolveLoadedConfig = async (options: RunCodegenOptions, cwd: string): Promise<LoadedConfig> =>
118
+ options.resolved ?? (await loadConfig(cwd, { mode: options.mode }));
119
+
120
+ const prepareCodegen = (options: RunCodegenOptions, cwd: string, config: Config): PreparedCodegen => {
121
+ const { girPath, libraries, store } = options.inputs ?? resolveCodegenInputs(cwd, config);
122
+
123
+ if (girPath.length === 0) {
124
+ throw new Error(GIR_PATH_MISSING_MESSAGE);
125
+ }
126
+
127
+ const isForce = options.force === true || isCodegenStale({ girPath, libraries, store });
128
+
129
+ return { girPath, libraries, store, force: isForce };
130
+ };
131
+
132
+ const runCodegen = async (options: RunCodegenOptions = {}): Promise<RunCodegenResult> => {
133
+ const cwd = options.cwd ?? process.cwd();
134
+ const { config, configFile } = await resolveLoadedConfig(options, cwd);
135
+
136
+ if (config.codegen === false) {
137
+ removeSharedStoreShadow(cwd);
138
+
139
+ return disabledCodegenResult(configFile);
140
+ }
141
+
142
+ const { girPath, libraries, store, force } = prepareCodegen(options, cwd, config);
143
+
144
+ if (options.force) {
145
+ clearGeneratedStores(store);
146
+ }
147
+
148
+ const result = await runCodegenCore({
149
+ ...codegenOptions({ store, libraries, girPath, elements: config.elements }),
150
+ force,
151
+ });
152
+
153
+ return {
154
+ regenerated: result.regenerated,
155
+ namespaces: result.namespaces,
156
+ intrinsicElements: result.intrinsicElements,
157
+ duration: result.duration,
158
+ girPath,
159
+ configFile,
160
+ libraries,
161
+ };
162
+ };
163
+
164
+ const isCodegenDisabled = async (cwd: string, mode?: string): Promise<boolean> => {
165
+ try {
166
+ const { config } = await loadConfig(cwd, { mode });
167
+
168
+ return config.codegen === false;
169
+ } catch {
170
+ return false;
171
+ }
172
+ };
173
+
174
+ const syncSchemaEnv = (cwd: string): void => {
175
+ emitSchemaEnv(cwd, resolveDataDir(cwd));
176
+ };
177
+
178
+ const resolveInputsOrNull = (cwd: string, config: Config): CodegenInputs | null => {
179
+ try {
180
+ return resolveCodegenInputs(cwd, config);
181
+ } catch {
182
+ return null;
183
+ }
184
+ };
185
+
186
+ const maybeAnnounceStale = (announce: boolean | undefined, inputs: CodegenInputs | null): void => {
187
+ if (!announce) {
188
+ return;
189
+ }
190
+
191
+ if (inputs === null || isCodegenStale(inputs)) {
192
+ info("generated bindings missing; running codegen...");
193
+ }
194
+ };
195
+
196
+ const getRunOptions = ({ root, mode, inputs, resolved }: RunOptionsInput): RunCodegenOptions => {
197
+ if (inputs === null) {
198
+ return { cwd: root, mode, resolved };
199
+ }
200
+
201
+ return { cwd: root, mode, inputs, resolved };
202
+ };
203
+
204
+ const ensureGenerated = async (
205
+ cwd: string,
206
+ options: { announce?: boolean; mode?: string } = {},
207
+ ): Promise<boolean> => {
208
+ if (options.announce && process.env.GTKX_DISABLE_PREFLIGHT === "1") {
209
+ return false;
210
+ }
211
+
212
+ const context = await resolveCodegenContext(cwd, options.mode);
213
+
214
+ if (!context) {
215
+ return false;
216
+ }
217
+
218
+ syncSchemaEnv(cwd);
219
+
220
+ if (context.config.codegen === false) {
221
+ removeSharedStoreShadow(context.root);
222
+
223
+ return false;
224
+ }
225
+
226
+ const inputs = resolveInputsOrNull(context.root, context.config);
227
+ maybeAnnounceStale(options.announce, inputs);
228
+ const resolved = { config: context.config, configFile: context.configFile };
229
+ const result = await runCodegen(getRunOptions({ root: context.root, mode: options.mode, inputs, resolved }));
230
+
231
+ return result.regenerated;
232
+ };
233
+
234
+ const resolveConfigWatch = async (
235
+ cwd: string,
236
+ mode?: string,
237
+ ): Promise<{ paths: string[]; regenerate: () => Promise<void> } | undefined> => {
238
+ const { configFile, root } = await loadConfig(cwd, { mode });
239
+
240
+ if (configFile === undefined) {
241
+ return undefined;
242
+ }
243
+
244
+ return {
245
+ paths: [resolve(root, configFile)],
246
+ regenerate: async () => {
247
+ await runCodegen({ cwd: root, mode });
248
+ },
249
+ };
250
+ };
251
+
252
+ export {
253
+ runCodegen,
254
+ isCodegenDisabled,
255
+ syncSchemaEnv,
256
+ ensureGenerated,
257
+ resolveConfigWatch,
258
+ type RunCodegenOptions,
259
+ type RunCodegenResult,
260
+ };
@@ -0,0 +1,116 @@
1
+ import { type Config, loadConfig } from "@gtkx/config";
2
+ import { existsSync, readFileSync, realpathSync } from "node:fs";
3
+ import { createRequire } from "node:module";
4
+ import { dirname, join } from "node:path";
5
+ import { pathToFileURL } from "node:url";
6
+
7
+ type CodegenStore = {
8
+ giStoreDir: string;
9
+ giLinkDir: string;
10
+ jsxStoreDir: string;
11
+ jsxLinkDir: string;
12
+ runtimeVersion: string;
13
+ react: CodegenReactPackage | null;
14
+ };
15
+
16
+ type CodegenReactPackage = {
17
+ version: string;
18
+ subexports: string[];
19
+ };
20
+
21
+ type ResolvedPackage = { dir: string; version: string };
22
+
23
+ type CodegenContext = {
24
+ root: string;
25
+ config: Config;
26
+ configFile: string | undefined;
27
+ };
28
+
29
+ const readVersion = (packageJsonPath: string): string => {
30
+ const parsed = JSON.parse(readFileSync(packageJsonPath, "utf8")) as { version?: string };
31
+
32
+ return parsed.version ?? "0.0.0";
33
+ };
34
+
35
+ const readSubexports = (packageDir: string): string[] => {
36
+ const parsed = JSON.parse(readFileSync(join(packageDir, "package.json"), "utf8")) as {
37
+ exports?: Record<string, unknown>;
38
+ };
39
+
40
+ return Object.keys(parsed.exports ?? {})
41
+ .filter((key) => key.startsWith("./") && key !== "./package.json")
42
+ .map((key) => key.slice(2));
43
+ };
44
+
45
+ /** Resolves the `@gtkx/react` subexport names for a project without requiring runtime/native to be installed. */
46
+ const resolveReactSubexports = (dir: string): string[] => {
47
+ const require = createRequire(pathToFileURL(join(dir, "__gtkx_resolver__.js")).href);
48
+ const react = resolvePackage(require, dir, "@gtkx/react");
49
+
50
+ return react === null ? [] : readSubexports(react.dir);
51
+ };
52
+
53
+ const resolvePackage = (require: NodeJS.Require, dir: string, packageName: string): ResolvedPackage | null => {
54
+ try {
55
+ const real = realpathSync(require.resolve(`${packageName}/package.json`));
56
+
57
+ return { dir: dirname(real), version: readVersion(real) };
58
+ } catch {
59
+ const unscoped = packageName.replace(/^@[^/]+\//, "");
60
+ const workspacePkg = join(dir, "packages", unscoped, "package.json");
61
+
62
+ if (!existsSync(workspacePkg)) {
63
+ return null;
64
+ }
65
+
66
+ const real = realpathSync(workspacePkg);
67
+
68
+ return { dir: dirname(real), version: readVersion(real) };
69
+ }
70
+ };
71
+
72
+ const resolveCodegenStore = (dir: string): CodegenStore => {
73
+ const require = createRequire(pathToFileURL(join(dir, "__gtkx_resolver__.js")).href);
74
+ const runtime = resolvePackage(require, dir, "@gtkx/runtime");
75
+
76
+ if (runtime === null) {
77
+ throw new Error("Cannot resolve @gtkx/runtime from the project; is it installed?");
78
+ }
79
+
80
+ const native = resolvePackage(require, dir, "@gtkx/native");
81
+
82
+ if (native === null) {
83
+ throw new Error("Cannot resolve @gtkx/native from the project; is it installed?");
84
+ }
85
+
86
+ const react = resolvePackage(require, dir, "@gtkx/react");
87
+ const reactRuntime = resolvePackage(require, dir, "react");
88
+ const nodeModules = join(dir, "node_modules");
89
+
90
+ return {
91
+ giStoreDir: join(nodeModules, ".gtkx", "gi"),
92
+ giLinkDir: join(nodeModules, "@gtkx", "gi"),
93
+ jsxStoreDir: join(nodeModules, ".gtkx", "jsx"),
94
+ jsxLinkDir: join(nodeModules, "@gtkx", "jsx"),
95
+ runtimeVersion: runtime.version,
96
+ react:
97
+ react !== null && reactRuntime !== null
98
+ ? {
99
+ version: react.version,
100
+ subexports: readSubexports(react.dir),
101
+ }
102
+ : null,
103
+ };
104
+ };
105
+
106
+ const resolveCodegenContext = async (cwd: string, mode?: string): Promise<CodegenContext | null> => {
107
+ const { config, configFile } = await loadConfig(cwd, { mode });
108
+
109
+ if (configFile === undefined) {
110
+ return null;
111
+ }
112
+
113
+ return { root: cwd, config, configFile };
114
+ };
115
+
116
+ export { resolveReactSubexports, resolveCodegenStore, resolveCodegenContext, type CodegenStore, type CodegenContext };
@@ -0,0 +1,38 @@
1
+ import { info } from "@gtkx/utils";
2
+ import { defineCommand } from "citty";
3
+ import { build as buildApp } from "../builder.js";
4
+ import { ensureGenerated } from "../codegen/run-codegen.js";
5
+ import { entryArg, resolveEntry } from "../internal/entry-arg.js";
6
+
7
+ const BUILD_MODE = "production";
8
+
9
+ const build = defineCommand({
10
+ meta: {
11
+ name: "build",
12
+ description: "Build application for production",
13
+ },
14
+ args: {
15
+ ...entryArg,
16
+ "asset-base": {
17
+ type: "string",
18
+ description: "Asset base path relative to executable directory (e.g., ../share/my-app)",
19
+ },
20
+ },
21
+ async run({ args }) {
22
+ const { cwd, entry } = resolveEntry(args);
23
+ info(`Building ${entry}`);
24
+ await ensureGenerated(cwd, { announce: true, mode: BUILD_MODE });
25
+
26
+ await buildApp({
27
+ entry,
28
+ assetBase: args["asset-base"],
29
+ vite: {
30
+ root: cwd,
31
+ },
32
+ });
33
+
34
+ info("Build complete: dist/bundle.js");
35
+ },
36
+ });
37
+
38
+ export { build };