vorma 0.0.0-pre.0 → 0.83.0

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 (225) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +48 -0
  3. package/internal/framework/_typescript/client/index.ts +64 -0
  4. package/internal/framework/_typescript/client/src/asset_manager.ts +67 -0
  5. package/internal/framework/_typescript/client/src/client.ts +1201 -0
  6. package/internal/framework/_typescript/client/src/client_loaders.ts +249 -0
  7. package/internal/framework/_typescript/client/src/component_loader.ts +105 -0
  8. package/internal/framework/_typescript/client/src/error_boundary.ts +7 -0
  9. package/internal/framework/_typescript/client/src/events.ts +54 -0
  10. package/internal/framework/_typescript/client/src/global_loading_indicator/global_loading_indicator.ts +125 -0
  11. package/internal/framework/_typescript/client/src/hard_reload.ts +1 -0
  12. package/internal/framework/_typescript/client/src/head_elements/head_elements.ts +193 -0
  13. package/internal/framework/_typescript/client/src/history/history.ts +118 -0
  14. package/internal/framework/_typescript/client/src/history/npm_history_types.ts +83 -0
  15. package/internal/framework/_typescript/client/src/hmr/hmr.ts +71 -0
  16. package/internal/framework/_typescript/client/src/init_client.ts +134 -0
  17. package/internal/framework/_typescript/client/src/links.ts +218 -0
  18. package/internal/framework/_typescript/client/src/redirects/redirects.ts +203 -0
  19. package/internal/framework/_typescript/client/src/rendering.ts +135 -0
  20. package/internal/framework/_typescript/client/src/resolve_public_href.ts +15 -0
  21. package/internal/framework/_typescript/client/src/scroll_state_manager.ts +100 -0
  22. package/internal/framework/_typescript/client/src/static_route_defs/route_def_helpers.ts +22 -0
  23. package/internal/framework/_typescript/client/src/ui_lib_impl_helpers/link_components.ts +131 -0
  24. package/internal/framework/_typescript/client/src/ui_lib_impl_helpers/route_components.ts +56 -0
  25. package/internal/framework/_typescript/client/src/ui_lib_impl_helpers/typed_navigate.ts +58 -0
  26. package/internal/framework/_typescript/client/src/utils/errors.ts +10 -0
  27. package/internal/framework/_typescript/client/src/utils/logging.ts +7 -0
  28. package/internal/framework/_typescript/client/src/vorma_app_helpers/vorma_app_helpers.ts +290 -0
  29. package/internal/framework/_typescript/client/src/vorma_ctx/vorma_ctx.ts +128 -0
  30. package/internal/framework/_typescript/client/src/window_focus_revalidation/window_focus_revalidation.ts +32 -0
  31. package/internal/framework/_typescript/client/tsconfig.json +3 -0
  32. package/internal/framework/_typescript/create/main.ts +378 -0
  33. package/internal/framework/_typescript/create/package.json +33 -0
  34. package/internal/framework/_typescript/create/pnpm-lock.yaml +70 -0
  35. package/internal/framework/_typescript/create/tsconfig.json +3 -0
  36. package/internal/framework/_typescript/preact/index.tsx +10 -0
  37. package/internal/framework/_typescript/preact/src/helpers.ts +113 -0
  38. package/internal/framework/_typescript/preact/src/link.tsx +107 -0
  39. package/internal/framework/_typescript/preact/src/preact.tsx +191 -0
  40. package/internal/framework/_typescript/preact/tsconfig.json +7 -0
  41. package/internal/framework/_typescript/react/index.tsx +10 -0
  42. package/internal/framework/_typescript/react/src/helpers.ts +118 -0
  43. package/internal/framework/_typescript/react/src/link.tsx +115 -0
  44. package/internal/framework/_typescript/react/src/react.tsx +299 -0
  45. package/internal/framework/_typescript/react/tsconfig.json +6 -0
  46. package/internal/framework/_typescript/solid/index.tsx +10 -0
  47. package/internal/framework/_typescript/solid/src/helpers.ts +114 -0
  48. package/internal/framework/_typescript/solid/src/link.tsx +104 -0
  49. package/internal/framework/_typescript/solid/src/solid.tsx +204 -0
  50. package/internal/framework/_typescript/solid/tsconfig.json +7 -0
  51. package/internal/framework/_typescript/vite/tsconfig.json +3 -0
  52. package/internal/framework/_typescript/vite/vite.ts +93 -0
  53. package/internal/site/frontend/assets/vorma-banner.webp +0 -0
  54. package/kit/_typescript/converters/converters.ts +152 -0
  55. package/kit/_typescript/cookies/cookies.ts +18 -0
  56. package/kit/_typescript/csrf/csrf.ts +10 -0
  57. package/kit/_typescript/debounce/debounce.ts +17 -0
  58. package/kit/_typescript/fmt/fmt.ts +3 -0
  59. package/kit/_typescript/json/deep_equals.ts +54 -0
  60. package/kit/_typescript/json/json.ts +3 -0
  61. package/kit/_typescript/json/search_param_serializer.ts +49 -0
  62. package/kit/_typescript/json/stringify_stable.ts +43 -0
  63. package/kit/_typescript/listeners/listeners.ts +16 -0
  64. package/kit/_typescript/matcher/find_best_match.ts +205 -0
  65. package/kit/_typescript/matcher/find_nested_matches.ts +357 -0
  66. package/kit/_typescript/matcher/parse_segments.ts +30 -0
  67. package/kit/_typescript/matcher/register.ts +271 -0
  68. package/kit/_typescript/theme/theme.ts +177 -0
  69. package/kit/_typescript/tsconfig.json +3 -0
  70. package/kit/_typescript/url/url.ts +132 -0
  71. package/npm_dist/internal/framework/_typescript/client/index.d.ts +17 -0
  72. package/npm_dist/internal/framework/_typescript/client/index.d.ts.map +1 -0
  73. package/npm_dist/internal/framework/_typescript/client/index.js +2489 -0
  74. package/npm_dist/internal/framework/_typescript/client/index.js.map +7 -0
  75. package/npm_dist/internal/framework/_typescript/client/src/asset_manager.d.ts +6 -0
  76. package/npm_dist/internal/framework/_typescript/client/src/asset_manager.d.ts.map +1 -0
  77. package/npm_dist/internal/framework/_typescript/client/src/client.d.ts +119 -0
  78. package/npm_dist/internal/framework/_typescript/client/src/client.d.ts.map +1 -0
  79. package/npm_dist/internal/framework/_typescript/client/src/client_loaders.d.ts +18 -0
  80. package/npm_dist/internal/framework/_typescript/client/src/client_loaders.d.ts.map +1 -0
  81. package/npm_dist/internal/framework/_typescript/client/src/component_loader.d.ts +10 -0
  82. package/npm_dist/internal/framework/_typescript/client/src/component_loader.d.ts.map +1 -0
  83. package/npm_dist/internal/framework/_typescript/client/src/error_boundary.d.ts +3 -0
  84. package/npm_dist/internal/framework/_typescript/client/src/error_boundary.d.ts.map +1 -0
  85. package/npm_dist/internal/framework/_typescript/client/src/events.d.ts +26 -0
  86. package/npm_dist/internal/framework/_typescript/client/src/events.d.ts.map +1 -0
  87. package/npm_dist/internal/framework/_typescript/client/src/global_loading_indicator/global_loading_indicator.d.ts +12 -0
  88. package/npm_dist/internal/framework/_typescript/client/src/global_loading_indicator/global_loading_indicator.d.ts.map +1 -0
  89. package/npm_dist/internal/framework/_typescript/client/src/hard_reload.d.ts +2 -0
  90. package/npm_dist/internal/framework/_typescript/client/src/hard_reload.d.ts.map +1 -0
  91. package/npm_dist/internal/framework/_typescript/client/src/head_elements/head_elements.d.ts +7 -0
  92. package/npm_dist/internal/framework/_typescript/client/src/head_elements/head_elements.d.ts.map +1 -0
  93. package/npm_dist/internal/framework/_typescript/client/src/history/history.d.ts +14 -0
  94. package/npm_dist/internal/framework/_typescript/client/src/history/history.d.ts.map +1 -0
  95. package/npm_dist/internal/framework/_typescript/client/src/history/npm_history_types.d.ts +84 -0
  96. package/npm_dist/internal/framework/_typescript/client/src/history/npm_history_types.d.ts.map +1 -0
  97. package/npm_dist/internal/framework/_typescript/client/src/hmr/hmr.d.ts +3 -0
  98. package/npm_dist/internal/framework/_typescript/client/src/hmr/hmr.d.ts.map +1 -0
  99. package/npm_dist/internal/framework/_typescript/client/src/init_client.d.ts +9 -0
  100. package/npm_dist/internal/framework/_typescript/client/src/init_client.d.ts.map +1 -0
  101. package/npm_dist/internal/framework/_typescript/client/src/links.d.ts +33 -0
  102. package/npm_dist/internal/framework/_typescript/client/src/links.d.ts.map +1 -0
  103. package/npm_dist/internal/framework/_typescript/client/src/redirects/redirects.d.ts +26 -0
  104. package/npm_dist/internal/framework/_typescript/client/src/redirects/redirects.d.ts.map +1 -0
  105. package/npm_dist/internal/framework/_typescript/client/src/rendering.d.ts +18 -0
  106. package/npm_dist/internal/framework/_typescript/client/src/rendering.d.ts.map +1 -0
  107. package/npm_dist/internal/framework/_typescript/client/src/resolve_public_href.d.ts +2 -0
  108. package/npm_dist/internal/framework/_typescript/client/src/resolve_public_href.d.ts.map +1 -0
  109. package/npm_dist/internal/framework/_typescript/client/src/scroll_state_manager.d.ts +22 -0
  110. package/npm_dist/internal/framework/_typescript/client/src/scroll_state_manager.d.ts.map +1 -0
  111. package/npm_dist/internal/framework/_typescript/client/src/static_route_defs/route_def_helpers.d.ts +12 -0
  112. package/npm_dist/internal/framework/_typescript/client/src/static_route_defs/route_def_helpers.d.ts.map +1 -0
  113. package/npm_dist/internal/framework/_typescript/client/src/ui_lib_impl_helpers/link_components.d.ts +28 -0
  114. package/npm_dist/internal/framework/_typescript/client/src/ui_lib_impl_helpers/link_components.d.ts.map +1 -0
  115. package/npm_dist/internal/framework/_typescript/client/src/ui_lib_impl_helpers/route_components.d.ts +18 -0
  116. package/npm_dist/internal/framework/_typescript/client/src/ui_lib_impl_helpers/route_components.d.ts.map +1 -0
  117. package/npm_dist/internal/framework/_typescript/client/src/ui_lib_impl_helpers/typed_navigate.d.ts +11 -0
  118. package/npm_dist/internal/framework/_typescript/client/src/ui_lib_impl_helpers/typed_navigate.d.ts.map +1 -0
  119. package/npm_dist/internal/framework/_typescript/client/src/utils/errors.d.ts +3 -0
  120. package/npm_dist/internal/framework/_typescript/client/src/utils/errors.d.ts.map +1 -0
  121. package/npm_dist/internal/framework/_typescript/client/src/utils/logging.d.ts +3 -0
  122. package/npm_dist/internal/framework/_typescript/client/src/utils/logging.d.ts.map +1 -0
  123. package/npm_dist/internal/framework/_typescript/client/src/vorma_app_helpers/vorma_app_helpers.d.ts +119 -0
  124. package/npm_dist/internal/framework/_typescript/client/src/vorma_app_helpers/vorma_app_helpers.d.ts.map +1 -0
  125. package/npm_dist/internal/framework/_typescript/client/src/vorma_ctx/vorma_ctx.d.ts +88 -0
  126. package/npm_dist/internal/framework/_typescript/client/src/vorma_ctx/vorma_ctx.d.ts.map +1 -0
  127. package/npm_dist/internal/framework/_typescript/client/src/window_focus_revalidation/window_focus_revalidation.d.ts +10 -0
  128. package/npm_dist/internal/framework/_typescript/client/src/window_focus_revalidation/window_focus_revalidation.d.ts.map +1 -0
  129. package/npm_dist/internal/framework/_typescript/create/main.d.ts +3 -0
  130. package/npm_dist/internal/framework/_typescript/create/main.d.ts.map +1 -0
  131. package/npm_dist/internal/framework/_typescript/preact/index.d.ts +4 -0
  132. package/npm_dist/internal/framework/_typescript/preact/index.d.ts.map +1 -0
  133. package/npm_dist/internal/framework/_typescript/preact/index.js +283 -0
  134. package/npm_dist/internal/framework/_typescript/preact/index.js.map +7 -0
  135. package/npm_dist/internal/framework/_typescript/preact/src/helpers.d.ts +21 -0
  136. package/npm_dist/internal/framework/_typescript/preact/src/helpers.d.ts.map +1 -0
  137. package/npm_dist/internal/framework/_typescript/preact/src/link.d.ts +11 -0
  138. package/npm_dist/internal/framework/_typescript/preact/src/link.d.ts.map +1 -0
  139. package/npm_dist/internal/framework/_typescript/preact/src/preact.d.ts +21 -0
  140. package/npm_dist/internal/framework/_typescript/preact/src/preact.d.ts.map +1 -0
  141. package/npm_dist/internal/framework/_typescript/react/index.d.ts +4 -0
  142. package/npm_dist/internal/framework/_typescript/react/index.d.ts.map +1 -0
  143. package/npm_dist/internal/framework/_typescript/react/index.js +370 -0
  144. package/npm_dist/internal/framework/_typescript/react/index.js.map +7 -0
  145. package/npm_dist/internal/framework/_typescript/react/src/helpers.d.ts +21 -0
  146. package/npm_dist/internal/framework/_typescript/react/src/helpers.d.ts.map +1 -0
  147. package/npm_dist/internal/framework/_typescript/react/src/link.d.ts +11 -0
  148. package/npm_dist/internal/framework/_typescript/react/src/link.d.ts.map +1 -0
  149. package/npm_dist/internal/framework/_typescript/react/src/react.d.ts +20 -0
  150. package/npm_dist/internal/framework/_typescript/react/src/react.d.ts.map +1 -0
  151. package/npm_dist/internal/framework/_typescript/solid/index.d.ts +4 -0
  152. package/npm_dist/internal/framework/_typescript/solid/index.d.ts.map +1 -0
  153. package/npm_dist/internal/framework/_typescript/solid/index.js +314 -0
  154. package/npm_dist/internal/framework/_typescript/solid/index.js.map +7 -0
  155. package/npm_dist/internal/framework/_typescript/solid/src/helpers.d.ts +22 -0
  156. package/npm_dist/internal/framework/_typescript/solid/src/helpers.d.ts.map +1 -0
  157. package/npm_dist/internal/framework/_typescript/solid/src/link.d.ts +11 -0
  158. package/npm_dist/internal/framework/_typescript/solid/src/link.d.ts.map +1 -0
  159. package/npm_dist/internal/framework/_typescript/solid/src/solid.d.ts +22 -0
  160. package/npm_dist/internal/framework/_typescript/solid/src/solid.d.ts.map +1 -0
  161. package/npm_dist/internal/framework/_typescript/vite/vite.d.ts +11 -0
  162. package/npm_dist/internal/framework/_typescript/vite/vite.d.ts.map +1 -0
  163. package/npm_dist/internal/framework/_typescript/vite/vite.js +82 -0
  164. package/npm_dist/internal/framework/_typescript/vite/vite.js.map +7 -0
  165. package/npm_dist/kit/_typescript/chunk-YBAPNBS2.js +202 -0
  166. package/npm_dist/kit/_typescript/chunk-YBAPNBS2.js.map +7 -0
  167. package/npm_dist/kit/_typescript/converters/converters.d.ts +26 -0
  168. package/npm_dist/kit/_typescript/converters/converters.d.ts.map +1 -0
  169. package/npm_dist/kit/_typescript/converters/converters.js +99 -0
  170. package/npm_dist/kit/_typescript/converters/converters.js.map +7 -0
  171. package/npm_dist/kit/_typescript/cookies/cookies.d.ts +13 -0
  172. package/npm_dist/kit/_typescript/cookies/cookies.d.ts.map +1 -0
  173. package/npm_dist/kit/_typescript/cookies/cookies.js +13 -0
  174. package/npm_dist/kit/_typescript/cookies/cookies.js.map +7 -0
  175. package/npm_dist/kit/_typescript/csrf/csrf.d.ts +5 -0
  176. package/npm_dist/kit/_typescript/csrf/csrf.d.ts.map +1 -0
  177. package/npm_dist/kit/_typescript/csrf/csrf.js +11 -0
  178. package/npm_dist/kit/_typescript/csrf/csrf.js.map +7 -0
  179. package/npm_dist/kit/_typescript/debounce/debounce.d.ts +4 -0
  180. package/npm_dist/kit/_typescript/debounce/debounce.d.ts.map +1 -0
  181. package/npm_dist/kit/_typescript/debounce/debounce.js +16 -0
  182. package/npm_dist/kit/_typescript/debounce/debounce.js.map +7 -0
  183. package/npm_dist/kit/_typescript/fmt/fmt.d.ts +2 -0
  184. package/npm_dist/kit/_typescript/fmt/fmt.d.ts.map +1 -0
  185. package/npm_dist/kit/_typescript/fmt/fmt.js +8 -0
  186. package/npm_dist/kit/_typescript/fmt/fmt.js.map +7 -0
  187. package/npm_dist/kit/_typescript/json/deep_equals.d.ts +7 -0
  188. package/npm_dist/kit/_typescript/json/deep_equals.d.ts.map +1 -0
  189. package/npm_dist/kit/_typescript/json/json.d.ts +4 -0
  190. package/npm_dist/kit/_typescript/json/json.d.ts.map +1 -0
  191. package/npm_dist/kit/_typescript/json/json.js +110 -0
  192. package/npm_dist/kit/_typescript/json/json.js.map +7 -0
  193. package/npm_dist/kit/_typescript/json/search_param_serializer.d.ts +2 -0
  194. package/npm_dist/kit/_typescript/json/search_param_serializer.d.ts.map +1 -0
  195. package/npm_dist/kit/_typescript/json/stringify_stable.d.ts +7 -0
  196. package/npm_dist/kit/_typescript/json/stringify_stable.d.ts.map +1 -0
  197. package/npm_dist/kit/_typescript/listeners/listeners.d.ts +2 -0
  198. package/npm_dist/kit/_typescript/listeners/listeners.d.ts.map +1 -0
  199. package/npm_dist/kit/_typescript/listeners/listeners.js +20 -0
  200. package/npm_dist/kit/_typescript/listeners/listeners.js.map +7 -0
  201. package/npm_dist/kit/_typescript/matcher/find_best_match.d.ts +10 -0
  202. package/npm_dist/kit/_typescript/matcher/find_best_match.d.ts.map +1 -0
  203. package/npm_dist/kit/_typescript/matcher/find_best_match.js +146 -0
  204. package/npm_dist/kit/_typescript/matcher/find_best_match.js.map +7 -0
  205. package/npm_dist/kit/_typescript/matcher/find_nested_matches.d.ts +14 -0
  206. package/npm_dist/kit/_typescript/matcher/find_nested_matches.d.ts.map +1 -0
  207. package/npm_dist/kit/_typescript/matcher/find_nested_matches.js +248 -0
  208. package/npm_dist/kit/_typescript/matcher/find_nested_matches.js.map +7 -0
  209. package/npm_dist/kit/_typescript/matcher/parse_segments.d.ts +2 -0
  210. package/npm_dist/kit/_typescript/matcher/parse_segments.d.ts.map +1 -0
  211. package/npm_dist/kit/_typescript/matcher/register.d.ts +54 -0
  212. package/npm_dist/kit/_typescript/matcher/register.d.ts.map +1 -0
  213. package/npm_dist/kit/_typescript/matcher/register.js +21 -0
  214. package/npm_dist/kit/_typescript/matcher/register.js.map +7 -0
  215. package/npm_dist/kit/_typescript/theme/theme.d.ts +24 -0
  216. package/npm_dist/kit/_typescript/theme/theme.d.ts.map +1 -0
  217. package/npm_dist/kit/_typescript/theme/theme.js +133 -0
  218. package/npm_dist/kit/_typescript/theme/theme.js.map +7 -0
  219. package/npm_dist/kit/_typescript/url/url.d.ts +30 -0
  220. package/npm_dist/kit/_typescript/url/url.d.ts.map +1 -0
  221. package/npm_dist/kit/_typescript/url/url.js +100 -0
  222. package/npm_dist/kit/_typescript/url/url.js.map +7 -0
  223. package/package.json +135 -3
  224. package/tsconfig.base.json +17 -0
  225. package/index.js +0 -1
@@ -0,0 +1,32 @@
1
+ import { addOnWindowFocusListener } from "vorma/kit/listeners";
2
+ import {
3
+ getLastTriggeredNavOrRevalidateTimestampMS,
4
+ getStatus,
5
+ revalidate,
6
+ } from "../client.ts";
7
+
8
+ /**
9
+ * If called, will setup listeners to revalidate the current route when
10
+ * the window regains focus and at least `staleTimeMS` has passed since
11
+ * the last revalidation. The `staleTimeMS` option defaults to 5,000
12
+ * (5 seconds). Returns a cleanup function.
13
+ */
14
+ export function revalidateOnWindowFocus(options?: { staleTimeMS?: number }) {
15
+ const staleTimeMS = options?.staleTimeMS ?? 5_000;
16
+ return addOnWindowFocusListener(() => {
17
+ const status = getStatus();
18
+ if (
19
+ !status.isNavigating &&
20
+ !status.isSubmitting &&
21
+ !status.isRevalidating
22
+ ) {
23
+ if (
24
+ Date.now() - getLastTriggeredNavOrRevalidateTimestampMS() <
25
+ staleTimeMS
26
+ ) {
27
+ return;
28
+ }
29
+ revalidate();
30
+ }
31
+ });
32
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "../../../../tsconfig.base.json"
3
+ }
@@ -0,0 +1,378 @@
1
+ #!/usr/bin/env node
2
+
3
+ import {
4
+ cancel,
5
+ confirm,
6
+ intro,
7
+ isCancel,
8
+ log,
9
+ select,
10
+ spinner,
11
+ text,
12
+ } from "@clack/prompts";
13
+ import { execSync } from "node:child_process";
14
+ import * as fs from "node:fs";
15
+ import * as os from "node:os";
16
+ import * as path from "node:path";
17
+ import { dirname } from "node:path";
18
+ import { fileURLToPath } from "node:url";
19
+
20
+ const __filename = fileURLToPath(import.meta.url);
21
+ const __dirname = dirname(__filename);
22
+
23
+ async function main() {
24
+ const args = process.argv.slice(2);
25
+ const isLocalTest = args.includes("--local-test");
26
+
27
+ console.log();
28
+ intro("Welcome to the Vorma new app creator!");
29
+
30
+ // Check Go installation
31
+ let goVersion = "";
32
+ try {
33
+ goVersion = execSync("go version", { encoding: "utf8" }).trim();
34
+ const versionMatch = goVersion.match(/go(\d+)\.(\d+)/);
35
+ if (versionMatch) {
36
+ if (!versionMatch[1] || !versionMatch[2]) {
37
+ cancel(
38
+ "Go version not recognized. Please ensure Go is installed correctly. See https://go.dev/doc/install for installation instructions.",
39
+ );
40
+ process.exit(1);
41
+ }
42
+ const major = parseInt(versionMatch[1]);
43
+ const minor = parseInt(versionMatch[2]);
44
+ if (major < 1 || (major === 1 && minor < 24)) {
45
+ cancel(
46
+ "Go version 1.24 or higher is required. See https://go.dev/doc/install for installation instructions.",
47
+ );
48
+ process.exit(1);
49
+ }
50
+ }
51
+ } catch {
52
+ cancel(
53
+ "Go is not installed. See https://go.dev/doc/install for installation instructions.",
54
+ );
55
+ process.exit(1);
56
+ }
57
+
58
+ // Check Node version
59
+ const nodeVersion = process.version;
60
+ const firstPart = nodeVersion.split(".")[0];
61
+ if (!firstPart || firstPart.length < 2 || !firstPart.startsWith("v")) {
62
+ cancel(
63
+ "Node.js version not recognized. Please ensure Node.js is installed correctly.",
64
+ );
65
+ process.exit(1);
66
+ }
67
+ const nodeMajor = parseInt(firstPart.substring(1));
68
+ if (nodeMajor < 22) {
69
+ cancel("Node.js version 22.11 or higher is required");
70
+ process.exit(1);
71
+ }
72
+
73
+ // Option to create a new directory at start if not already in desired location
74
+ const createNewDir = await confirm({
75
+ message: "Create a new directory for your Vorma app?",
76
+ initialValue: true,
77
+ });
78
+
79
+ if (isCancel(createNewDir)) {
80
+ cancel("Operation cancelled");
81
+ process.exit(0);
82
+ }
83
+
84
+ let targetDir = process.cwd();
85
+
86
+ if (createNewDir) {
87
+ const dirName = await text({
88
+ message: "Enter directory name:",
89
+ validate: (value) => {
90
+ if (!value || value.trim() === "")
91
+ return "Directory name is required";
92
+ // Check for invalid characters in directory name
93
+ if (!/^[a-zA-Z0-9-_]+$/.test(value)) {
94
+ return "Directory name can only contain letters, numbers, hyphens, and underscores";
95
+ }
96
+ // Check if directory already exists
97
+ const proposedPath = path.join(process.cwd(), value);
98
+ if (fs.existsSync(proposedPath)) {
99
+ return `Directory "${value}" already exists`;
100
+ }
101
+ return undefined;
102
+ },
103
+ });
104
+
105
+ if (isCancel(dirName)) {
106
+ cancel("Operation cancelled");
107
+ process.exit(0);
108
+ }
109
+
110
+ // Create the directory and change to it
111
+ targetDir = path.join(process.cwd(), dirName as string);
112
+ fs.mkdirSync(targetDir, { recursive: true });
113
+ process.chdir(targetDir);
114
+ log.success(`Created directory: ${dirName}`);
115
+ }
116
+
117
+ // Find go.mod and determine import path
118
+ let goModPath: string | null = null;
119
+ let moduleRoot: string | null = null;
120
+ let moduleName: string | null = null;
121
+ let createNewModule = false;
122
+
123
+ // Search for go.mod
124
+ let currentDir = process.cwd();
125
+ while (currentDir !== path.dirname(currentDir)) {
126
+ const modPath = path.join(currentDir, "go.mod");
127
+ if (fs.existsSync(modPath)) {
128
+ goModPath = modPath;
129
+ moduleRoot = currentDir;
130
+ break;
131
+ }
132
+ currentDir = path.dirname(currentDir);
133
+ }
134
+
135
+ // Parse module name if found
136
+ if (goModPath) {
137
+ const modContent = fs.readFileSync(goModPath, "utf8");
138
+ const moduleMatch = modContent.match(/^module\s+(.+)$/m);
139
+ if (moduleMatch && moduleMatch[1]) {
140
+ moduleName = moduleMatch[1].trim();
141
+ }
142
+
143
+ // When module is found, give option to use it or create nested module
144
+ const moduleChoice = await select({
145
+ message: `Found parent Go module: ${moduleName}`,
146
+ options: [
147
+ { value: "new", label: "Create new go.mod" },
148
+ { value: "use", label: "Use parent go.mod" },
149
+ ],
150
+ });
151
+
152
+ if (isCancel(moduleChoice)) {
153
+ cancel("Operation cancelled");
154
+ process.exit(0);
155
+ }
156
+
157
+ if (moduleChoice === "new") {
158
+ createNewModule = true;
159
+ // Reset module info since we're creating a new one
160
+ goModPath = null;
161
+ moduleRoot = null;
162
+ moduleName = null;
163
+ }
164
+ } else {
165
+ // No module found, we need to create one
166
+ createNewModule = true;
167
+ }
168
+
169
+ // Handle go.mod initialization if needed
170
+ if (createNewModule) {
171
+ const modNameInput = await text({
172
+ message:
173
+ 'Enter module name (e.g., "myapp" or "github.com/user/myapp"):',
174
+ validate: (value) => {
175
+ if (!value || value.trim() === "")
176
+ return "Module name is required";
177
+ return undefined;
178
+ },
179
+ });
180
+
181
+ if (isCancel(modNameInput)) {
182
+ cancel("Operation cancelled");
183
+ process.exit(0);
184
+ }
185
+
186
+ moduleName = modNameInput as string;
187
+ moduleRoot = process.cwd();
188
+
189
+ const s = spinner();
190
+ s.start("Initializing Go module");
191
+ try {
192
+ execSync(`go mod init ${moduleName}`, { cwd: moduleRoot });
193
+ if (isLocalTest) {
194
+ const vormaPath = path.resolve(__dirname, "../../../../../");
195
+ execSync(
196
+ `go mod edit -replace github.com/vormadev/vorma=${vormaPath}`,
197
+ { cwd: moduleRoot },
198
+ );
199
+ log.info("Using local Vorma code for testing");
200
+ }
201
+ s.stop("Go module initialized");
202
+ } catch (error) {
203
+ s.stop("Failed to initialize module");
204
+ cancel(`Error: ${error}`);
205
+ process.exit(1);
206
+ }
207
+ }
208
+
209
+ // Check for underscore directories from module root to current directory
210
+ const pathFromModuleRoot = moduleRoot
211
+ ? path.relative(moduleRoot, process.cwd())
212
+ : "";
213
+ const pathSegments = pathFromModuleRoot
214
+ .split(path.sep)
215
+ .filter((seg) => seg.length > 0);
216
+ const underscoreSegments = pathSegments.filter((seg) =>
217
+ seg.startsWith("_"),
218
+ );
219
+ if (underscoreSegments.length > 0) {
220
+ cancel(
221
+ `Cannot create Vorma app in a path containing directories that start with underscores:\n ${underscoreSegments.join(", ")}\n` +
222
+ ` Go ignores directories starting with underscores, which will cause build issues.`,
223
+ );
224
+ process.exit(1);
225
+ }
226
+
227
+ // Calculate import path automatically
228
+ let importPath = moduleName!;
229
+ if (moduleRoot !== process.cwd()) {
230
+ const relativePath = path.relative(moduleRoot!, process.cwd());
231
+ importPath = path.posix.join(
232
+ moduleName!,
233
+ ...relativePath.split(path.sep),
234
+ );
235
+ }
236
+
237
+ // Collect options
238
+ const uiVariant = await select({
239
+ message: "Choose frontend UI library:",
240
+ options: [
241
+ { value: "react", label: "React" },
242
+ { value: "preact", label: "Preact" },
243
+ { value: "solid", label: "Solid" },
244
+ ],
245
+ });
246
+
247
+ if (isCancel(uiVariant)) {
248
+ cancel("Operation cancelled");
249
+ process.exit(0);
250
+ }
251
+
252
+ const packageManager = (await select({
253
+ message: "Choose JS package manager:",
254
+ options: [
255
+ { value: "npm", label: "npm" },
256
+ { value: "pnpm", label: "pnpm" },
257
+ { value: "yarn", label: "yarn" },
258
+ { value: "bun", label: "bun" },
259
+ ],
260
+ })) as string;
261
+
262
+ if (isCancel(packageManager)) {
263
+ cancel("Operation cancelled");
264
+ process.exit(0);
265
+ }
266
+
267
+ const deploymentTarget = await select({
268
+ message: "Choose deployment target:",
269
+ options: [
270
+ {
271
+ value: "docker",
272
+ label: "Docker",
273
+ },
274
+ {
275
+ value: "vercel",
276
+ label: "Vercel",
277
+ },
278
+ {
279
+ value: "none",
280
+ label: "None (I'll figure it out myself)",
281
+ },
282
+ ],
283
+ });
284
+
285
+ if (isCancel(deploymentTarget)) {
286
+ cancel("Operation cancelled");
287
+ process.exit(0);
288
+ }
289
+
290
+ // Ask about Tailwind CSS
291
+ const includeTailwind = await confirm({
292
+ message: "Include Tailwind CSS?",
293
+ initialValue: false,
294
+ });
295
+
296
+ if (isCancel(includeTailwind)) {
297
+ cancel("Operation cancelled");
298
+ process.exit(0);
299
+ }
300
+
301
+ console.log();
302
+ console.log("🛠️ Preparing bootstrapper...");
303
+
304
+ // Create temporary directory
305
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "create-vorma-"));
306
+ const bootstrapFile = path.join(tempDir, "main.go");
307
+
308
+ // Extract Go version string (e.g., "go1.24.0")
309
+ const goVersionMatch = goVersion.match(/go\d+\.\d+\.\d+/);
310
+ const goVersionString = goVersionMatch ? goVersionMatch[0] : "";
311
+
312
+ try {
313
+ // Write bootstrap Go file
314
+ const goCode = `package main
315
+
316
+ import "github.com/vormadev/vorma/bootstrap"
317
+
318
+ func main() {
319
+ bootstrap.Init(bootstrap.Options{
320
+ GoImportBase: "${importPath}",
321
+ UIVariant: "${uiVariant}",
322
+ JSPackageManager: "${packageManager}",
323
+ DeploymentTarget: "${deploymentTarget}",
324
+ IncludeTailwind: ${includeTailwind},
325
+ NodeMajorVersion: "${nodeMajor}",
326
+ GoVersion: "${goVersionString}",
327
+ ${createNewDir ? `CreatedInDir: "${path.basename(targetDir)}",` : ""}
328
+ ModuleRoot: "${moduleRoot || process.cwd()}",
329
+ CurrentDir: "${process.cwd()}",
330
+ HasParentModule: ${moduleRoot !== null && moduleRoot !== process.cwd()},
331
+ })
332
+ }
333
+ `;
334
+ fs.writeFileSync(bootstrapFile, goCode);
335
+
336
+ // Install Vorma dependency
337
+ const packageJsonPath = path.join(__dirname, "../package.json");
338
+ const packageJson = JSON.parse(
339
+ fs.readFileSync(packageJsonPath, "utf8"),
340
+ );
341
+ const version = packageJson.version;
342
+ const usingExistingModule = !createNewModule;
343
+ const skipVormaGet = isLocalTest && usingExistingModule;
344
+ if (!skipVormaGet) {
345
+ execSync(`go get github.com/vormadev/vorma@v${version}`, {
346
+ cwd: process.cwd(),
347
+ stdio: "pipe",
348
+ });
349
+ }
350
+
351
+ // Run bootstrap
352
+ console.log("🛠️ Running bootstrapper...");
353
+ try {
354
+ execSync(`go run ${bootstrapFile}`, {
355
+ cwd: process.cwd(),
356
+ stdio: "inherit",
357
+ });
358
+ } catch (error) {
359
+ console.error("Failed to create app");
360
+ throw error;
361
+ }
362
+ } catch (error) {
363
+ cancel(`Error: ${error}`);
364
+ process.exit(1);
365
+ } finally {
366
+ // Clean up temp directory
367
+ try {
368
+ fs.rmSync(tempDir, { recursive: true, force: true });
369
+ } catch {
370
+ // Ignore cleanup errors
371
+ }
372
+ }
373
+ }
374
+
375
+ main().catch((error) => {
376
+ console.error("Unexpected error:", error);
377
+ process.exit(1);
378
+ });
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "create-vorma",
3
+ "version": "0.83.0",
4
+ "description": "CLI for creating new Vorma applications.",
5
+ "type": "module",
6
+ "license": "BSD-3-Clause",
7
+ "repository": {
8
+ "url": "https://github.com/vormadev/vorma",
9
+ "type": "git",
10
+ "directory": "internal/framework/_typescript/create"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/vormadev/vorma/issues"
14
+ },
15
+ "homepage": "https://vorma.dev",
16
+ "author": "Samuel J. Cook",
17
+ "bin": {
18
+ "create-vorma": "./dist/main.js"
19
+ },
20
+ "files": [
21
+ "dist"
22
+ ],
23
+ "dependencies": {
24
+ "@clack/prompts": "^0.11.0"
25
+ },
26
+ "devDependencies": {
27
+ "@types/node": "^24.2.1",
28
+ "typescript": "^5.9.2"
29
+ },
30
+ "engines": {
31
+ "node": ">=22.11.0"
32
+ }
33
+ }
@@ -0,0 +1,70 @@
1
+ lockfileVersion: '9.0'
2
+
3
+ settings:
4
+ autoInstallPeers: true
5
+ excludeLinksFromLockfile: false
6
+
7
+ importers:
8
+
9
+ .:
10
+ dependencies:
11
+ '@clack/prompts':
12
+ specifier: ^0.11.0
13
+ version: 0.11.0
14
+ devDependencies:
15
+ '@types/node':
16
+ specifier: ^24.2.1
17
+ version: 24.2.1
18
+ typescript:
19
+ specifier: ^5.9.2
20
+ version: 5.9.2
21
+
22
+ packages:
23
+
24
+ '@clack/core@0.5.0':
25
+ resolution: {integrity: sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow==}
26
+
27
+ '@clack/prompts@0.11.0':
28
+ resolution: {integrity: sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw==}
29
+
30
+ '@types/node@24.2.1':
31
+ resolution: {integrity: sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ==}
32
+
33
+ picocolors@1.1.1:
34
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
35
+
36
+ sisteransi@1.0.5:
37
+ resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
38
+
39
+ typescript@5.9.2:
40
+ resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==}
41
+ engines: {node: '>=14.17'}
42
+ hasBin: true
43
+
44
+ undici-types@7.10.0:
45
+ resolution: {integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==}
46
+
47
+ snapshots:
48
+
49
+ '@clack/core@0.5.0':
50
+ dependencies:
51
+ picocolors: 1.1.1
52
+ sisteransi: 1.0.5
53
+
54
+ '@clack/prompts@0.11.0':
55
+ dependencies:
56
+ '@clack/core': 0.5.0
57
+ picocolors: 1.1.1
58
+ sisteransi: 1.0.5
59
+
60
+ '@types/node@24.2.1':
61
+ dependencies:
62
+ undici-types: 7.10.0
63
+
64
+ picocolors@1.1.1: {}
65
+
66
+ sisteransi@1.0.5: {}
67
+
68
+ typescript@5.9.2: {}
69
+
70
+ undici-types@7.10.0: {}
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "../../../../tsconfig.base.json"
3
+ }
@@ -0,0 +1,10 @@
1
+ export {
2
+ makeTypedAddClientLoader,
3
+ makeTypedUseLoaderData,
4
+ makeTypedUsePatternLoaderData,
5
+ makeTypedUseRouterData,
6
+ type VormaRoute,
7
+ type VormaRouteProps,
8
+ } from "./src/helpers.ts";
9
+ export { VormaLink, makeTypedLink } from "./src/link.tsx";
10
+ export { VormaRootOutlet, location } from "./src/preact.tsx";
@@ -0,0 +1,113 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ import { useMemo } from "preact/hooks";
4
+ import type { JSX } from "preact/jsx-runtime";
5
+ import {
6
+ __registerClientLoaderPattern,
7
+ __runClientLoadersAfterHMRUpdate,
8
+ __vormaClientGlobal,
9
+ type ClientLoaderAwaitedServerData,
10
+ type ParamsForPattern,
11
+ type UseRouterDataFunction,
12
+ type VormaAppBase,
13
+ type VormaLoaderOutput,
14
+ type VormaLoaderPattern,
15
+ type VormaRouteGeneric,
16
+ type VormaRoutePropsGeneric,
17
+ } from "vorma/client";
18
+ import { clientLoadersData, loadersData, routerData } from "./preact.tsx";
19
+
20
+ export type VormaRouteProps<
21
+ App extends VormaAppBase = any,
22
+ Pattern extends VormaLoaderPattern<App> = string,
23
+ > = VormaRoutePropsGeneric<JSX.Element, App, Pattern>;
24
+
25
+ export type VormaRoute<
26
+ App extends VormaAppBase = any,
27
+ Pattern extends VormaLoaderPattern<App> = string,
28
+ > = VormaRouteGeneric<JSX.Element, App, Pattern>;
29
+
30
+ export function makeTypedUseRouterData<App extends VormaAppBase>() {
31
+ return (() => {
32
+ return routerData.value;
33
+ }) as UseRouterDataFunction<App, false>;
34
+ }
35
+
36
+ export function makeTypedUseLoaderData<App extends VormaAppBase>() {
37
+ return function useLoaderData<Pattern extends VormaLoaderPattern<App>>(
38
+ props: VormaRouteProps<App, Pattern>,
39
+ ): VormaLoaderOutput<App, Pattern> {
40
+ return loadersData.value[props.idx];
41
+ };
42
+ }
43
+
44
+ export function makeTypedUsePatternLoaderData<App extends VormaAppBase>() {
45
+ return function usePatternLoaderData<
46
+ Pattern extends VormaLoaderPattern<App>,
47
+ >(pattern: Pattern): VormaLoaderOutput<App, Pattern> | undefined {
48
+ const idx = useMemo(() => {
49
+ return routerData.value.matchedPatterns.findIndex(
50
+ (p) => p === pattern,
51
+ );
52
+ }, [pattern]);
53
+
54
+ if (idx === -1) {
55
+ return undefined;
56
+ }
57
+ return loadersData.value[idx];
58
+ };
59
+ }
60
+
61
+ export function makeTypedAddClientLoader<App extends VormaAppBase>() {
62
+ const m = __vormaClientGlobal.get("patternToWaitFnMap");
63
+ return function addClientLoader<
64
+ Pattern extends VormaLoaderPattern<App>,
65
+ LoaderData extends VormaLoaderOutput<App, Pattern>,
66
+ T = any,
67
+ >(props: {
68
+ pattern: Pattern;
69
+ clientLoader: (props: {
70
+ params: Record<ParamsForPattern<App, Pattern>, string>;
71
+ splatValues: string[];
72
+ serverDataPromise: Promise<
73
+ ClientLoaderAwaitedServerData<App["rootData"], LoaderData>
74
+ >;
75
+ signal: AbortSignal;
76
+ }) => Promise<T>;
77
+ reRunOnModuleChange?: ImportMeta;
78
+ }) {
79
+ const p = props.pattern;
80
+ const fn = props.clientLoader;
81
+
82
+ __registerClientLoaderPattern(p as string).catch((error) => {
83
+ console.error("Failed to register client loader pattern:", error);
84
+ });
85
+ (m as any)[p] = fn;
86
+
87
+ if (import.meta.env.DEV && props.reRunOnModuleChange) {
88
+ __runClientLoadersAfterHMRUpdate(props.reRunOnModuleChange, p);
89
+ }
90
+
91
+ type Res = Awaited<ReturnType<typeof fn>>;
92
+
93
+ const useClientLoaderData = (
94
+ props?: VormaRouteProps<App, Pattern>,
95
+ ): Res | undefined => {
96
+ const idx = useMemo(() => {
97
+ if (props) {
98
+ return props.idx;
99
+ }
100
+ const matched = routerData.value.matchedPatterns;
101
+ return matched.findIndex((pattern) => pattern === p);
102
+ }, [props]);
103
+
104
+ if (idx === -1) return undefined;
105
+ return clientLoadersData.value[idx];
106
+ };
107
+
108
+ return useClientLoaderData as {
109
+ (props: VormaRouteProps<App, Pattern>): Res;
110
+ (): Res | undefined;
111
+ };
112
+ };
113
+ }