@lazarv/create-react-server 0.0.0-experimental-d003259-20250211-2495688e

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 (95) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +31 -0
  3. package/generator.mjs +195 -0
  4. package/globals.d.ts +59 -0
  5. package/index.mjs +87 -0
  6. package/launch.mjs +136 -0
  7. package/lib/code-merge.mjs +246 -0
  8. package/lib/dynamic-checkbox.mjs +259 -0
  9. package/lib/files.mjs +6 -0
  10. package/lib/formatter.mjs +16 -0
  11. package/lib/generate-name.mjs +220 -0
  12. package/lib/theme.mjs +56 -0
  13. package/logo.mjs +3 -0
  14. package/package.json +26 -0
  15. package/steps/alias.mjs +50 -0
  16. package/steps/authentication.mjs +62 -0
  17. package/steps/database.mjs +56 -0
  18. package/steps/deploy.mjs +151 -0
  19. package/steps/features.mjs +415 -0
  20. package/steps/host.mjs +40 -0
  21. package/steps/index.mjs +33 -0
  22. package/steps/integrations.mjs +104 -0
  23. package/steps/name.mjs +69 -0
  24. package/steps/package.mjs +104 -0
  25. package/steps/port.mjs +42 -0
  26. package/steps/preset.mjs +188 -0
  27. package/steps/state-management.mjs +68 -0
  28. package/steps/third-party.mjs +19 -0
  29. package/steps/ui.mjs +87 -0
  30. package/templates/.dockerignore +5 -0
  31. package/templates/.gitignore.template +19 -0
  32. package/templates/.prettierignore +3 -0
  33. package/templates/.prettierrc +11 -0
  34. package/templates/Dockerfile.npm +49 -0
  35. package/templates/Dockerfile.pnpm +71 -0
  36. package/templates/Dockerfile.yarn +71 -0
  37. package/templates/README.docker.md +15 -0
  38. package/templates/README.md +35 -0
  39. package/templates/blank/package.json +6 -0
  40. package/templates/blank/src/App.jsx +5 -0
  41. package/templates/blank-ts/package.json +6 -0
  42. package/templates/blank-ts/src/App.tsx +5 -0
  43. package/templates/eslint.config.template.mjs +98 -0
  44. package/templates/get-started/package.json +6 -0
  45. package/templates/get-started/src/App.jsx +60 -0
  46. package/templates/get-started/src/Button.jsx +14 -0
  47. package/templates/get-started/src/Confetti.jsx +19 -0
  48. package/templates/get-started/src/global.css +3 -0
  49. package/templates/get-started-ts/globals.d.ts +3 -0
  50. package/templates/get-started-ts/package.json +6 -0
  51. package/templates/get-started-ts/src/App.tsx +66 -0
  52. package/templates/get-started-ts/src/Button.tsx +18 -0
  53. package/templates/get-started-ts/src/Confetti.tsx +19 -0
  54. package/templates/get-started-ts/src/global.css +3 -0
  55. package/templates/nextjs/globals.d.ts +3 -0
  56. package/templates/nextjs/react-server.config.json +9 -0
  57. package/templates/nextjs/src/app/layout.tsx +38 -0
  58. package/templates/nextjs/src/app/page.tsx +33 -0
  59. package/templates/nextjs/src/components/Button.tsx +18 -0
  60. package/templates/nextjs/src/components/Confetti.tsx +19 -0
  61. package/templates/nextjs/src/global.css +3 -0
  62. package/templates/package.css.json +5 -0
  63. package/templates/package.eslint.json +19 -0
  64. package/templates/package.eslint.ts.json +7 -0
  65. package/templates/package.json +12 -0
  66. package/templates/package.lightningcss.json +6 -0
  67. package/templates/package.prettier.json +8 -0
  68. package/templates/package.react-compiler.json +7 -0
  69. package/templates/package.swc.json +5 -0
  70. package/templates/package.tailwind.json +7 -0
  71. package/templates/package.ts.json +11 -0
  72. package/templates/postcss.config.mjs +6 -0
  73. package/templates/router/globals.d.ts +3 -0
  74. package/templates/router/react-server.config.json +19 -0
  75. package/templates/router/src/app/@content/about.tsx +98 -0
  76. package/templates/router/src/app/@content/index.tsx +33 -0
  77. package/templates/router/src/app/layout.tsx +44 -0
  78. package/templates/router/src/app/page.tsx +17 -0
  79. package/templates/router/src/components/Button.tsx +18 -0
  80. package/templates/router/src/components/Confetti.tsx +19 -0
  81. package/templates/router/src/components/Navigation.tsx +31 -0
  82. package/templates/router/src/global.css +3 -0
  83. package/templates/shared/public/github.svg +4 -0
  84. package/templates/shared/public/react-server.svg +51 -0
  85. package/templates/tailwind.config.mjs +6 -0
  86. package/templates/tsconfig.css.json +9 -0
  87. package/templates/tsconfig.template.json +15 -0
  88. package/templates/vite.config.lightningcss.mjs +15 -0
  89. package/templates/vite.config.lightningcss.ts +15 -0
  90. package/templates/vite.config.react-compiler.mjs +19 -0
  91. package/templates/vite.config.react-compiler.ts +19 -0
  92. package/templates/vite.config.swc.mjs +6 -0
  93. package/templates/vite.config.swc.ts +6 -0
  94. package/templates/vite.config.ts +3 -0
  95. package/wizard.mjs +122 -0
@@ -0,0 +1,220 @@
1
+ const adjectives = [
2
+ "mystical",
3
+ "arcane",
4
+ "enchanted",
5
+ "mysterious",
6
+ "bewitched",
7
+ "magical",
8
+ "celestial",
9
+ "luminous",
10
+ "abyssal",
11
+ "divine",
12
+ "astral",
13
+ "transcendent",
14
+ "ethereal",
15
+ "enigmatic",
16
+ "cursed",
17
+ "ancient",
18
+ "whispering",
19
+ "phantasmal",
20
+ "runic",
21
+ "sorcerous",
22
+ "fabled",
23
+ "shadowed",
24
+ "hidden",
25
+ "glimmering",
26
+ "eldritch",
27
+ "vortex",
28
+ "infernal",
29
+ "empyrean",
30
+ "elemental",
31
+ "primeval",
32
+ "radiant",
33
+ "mystic",
34
+ "vengeful",
35
+ "ghostly",
36
+ "supernatural",
37
+ "cryptic",
38
+ "prophetic",
39
+ "timeless",
40
+ "warded",
41
+ "occult",
42
+ "chaotic",
43
+ "celestial",
44
+ "galactic",
45
+ "quantum",
46
+ "spectral",
47
+ "illusive",
48
+ "veiled",
49
+ "shrouded",
50
+ "arcadian",
51
+ "unseen",
52
+ "frosted",
53
+ "shimmering",
54
+ "glacial",
55
+ "obscured",
56
+ "vibrant",
57
+ "warped",
58
+ "fractal",
59
+ "brilliant",
60
+ "empowered",
61
+ "flickering",
62
+ "arcadian",
63
+ "prismatic",
64
+ "stellar",
65
+ "etheric",
66
+ "illuminated",
67
+ "chromatic",
68
+ "boundless",
69
+ "cascading",
70
+ "unfathomable",
71
+ "mercurial",
72
+ "turbulent",
73
+ "obscure",
74
+ "dimensional",
75
+ "perpetual",
76
+ "revered",
77
+ "eclipsed",
78
+ "timeless",
79
+ "lucid",
80
+ "runic",
81
+ "arcane",
82
+ "infinite",
83
+ "dynamic",
84
+ "invoked",
85
+ "reactive",
86
+ "atomic",
87
+ "concurrent",
88
+ "asynchronous",
89
+ "serverless",
90
+ "virtual",
91
+ "distributed",
92
+ "scalable",
93
+ "fluid",
94
+ "stateless",
95
+ "streamlined",
96
+ "encrypted",
97
+ "isomorphic",
98
+ "immutable",
99
+ "optimized",
100
+ "efficient",
101
+ "ephemeral",
102
+ "concurrent",
103
+ "abstract",
104
+ ];
105
+ const nouns = [
106
+ "sorcerer",
107
+ "spellbinder",
108
+ "enchanter",
109
+ "mage",
110
+ "alchemist",
111
+ "conjurer",
112
+ "warlock",
113
+ "wizardry",
114
+ "spellbook",
115
+ "rune",
116
+ "arcana",
117
+ "elementalist",
118
+ "mystic",
119
+ "diviner",
120
+ "seer",
121
+ "illusionist",
122
+ "hex",
123
+ "charm",
124
+ "amulet",
125
+ "elixir",
126
+ "incantation",
127
+ "potions",
128
+ "grimoire",
129
+ "familiar",
130
+ "enchantment",
131
+ "portal",
132
+ "oracle",
133
+ "summoner",
134
+ "archmage",
135
+ "necromancer",
136
+ "shade",
137
+ "phantasm",
138
+ "aether",
139
+ "catalyst",
140
+ "astral",
141
+ "ember",
142
+ "druid",
143
+ "glyph",
144
+ "constellation",
145
+ "realm",
146
+ "scepter",
147
+ "obelisk",
148
+ "relic",
149
+ "specter",
150
+ "golem",
151
+ "wyrm",
152
+ "phoenix",
153
+ "basilisk",
154
+ "drake",
155
+ "conduit",
156
+ "scroll",
157
+ "nexus",
158
+ "talisman",
159
+ "familiar",
160
+ "sorcery",
161
+ "incantation",
162
+ "summoning",
163
+ "transmutation",
164
+ "arcane",
165
+ "crystal",
166
+ "ether",
167
+ "shade",
168
+ "rune",
169
+ "ward",
170
+ "node",
171
+ "shaman",
172
+ "element",
173
+ "astral",
174
+ "paragon",
175
+ "sigil",
176
+ "invoker",
177
+ "aura",
178
+ "specter",
179
+ "oracle",
180
+ "aegis",
181
+ "forge",
182
+ "prism",
183
+ "shade",
184
+ "invocation",
185
+ "codex",
186
+ "shroud",
187
+ "beacon",
188
+ "rift",
189
+ "warden",
190
+ "channeler",
191
+ "elemental",
192
+ "mysticism",
193
+ "wizard",
194
+ "server",
195
+ "reactor",
196
+ "framework",
197
+ "component",
198
+ "dispatcher",
199
+ "middleware",
200
+ "portal",
201
+ "cache",
202
+ "observer",
203
+ "cluster",
204
+ "daemon",
205
+ "thread",
206
+ "wizardry",
207
+ "prophet",
208
+ "guardian",
209
+ "host",
210
+ ];
211
+
212
+ function getRandomElement(arr) {
213
+ return arr[Math.floor(Math.random() * arr.length)];
214
+ }
215
+
216
+ export function generateProjectName() {
217
+ const adjective = getRandomElement(adjectives);
218
+ const noun = getRandomElement(nouns);
219
+ return `${adjective}-${noun}`;
220
+ }
package/lib/theme.mjs ADDED
@@ -0,0 +1,56 @@
1
+ import colors from "picocolors";
2
+
3
+ const timeFormatter = new Intl.DateTimeFormat(undefined, {
4
+ hour: "numeric",
5
+ minute: "numeric",
6
+ second: "numeric",
7
+ });
8
+
9
+ const logColors = {
10
+ info: colors.cyan,
11
+ error: colors.red,
12
+ warn: colors.yellow,
13
+ };
14
+
15
+ export const createTheme = (type = "info", context) => ({
16
+ prefix: {
17
+ idle:
18
+ colors.gray(timeFormatter.format(new Date())) +
19
+ colors.bold(logColors[type](" [react-server]")),
20
+ done:
21
+ colors.gray(timeFormatter.format(new Date())) +
22
+ colors.bold(logColors[type](" [react-server]")),
23
+ },
24
+ icon: {
25
+ checked: "✅",
26
+ unchecked: " ",
27
+ cursor: " ",
28
+ },
29
+ style: {
30
+ answer: colors.white,
31
+ highlight: (message) => colors.bold(colors.magenta(message)),
32
+ message: (message) =>
33
+ (message ? `${colors.white(message)} ` : "") + colors.green("➜"),
34
+ renderSelectedChoices: (selected) => {
35
+ const choices = [
36
+ ...(context?.props?.preset?.features ?? []),
37
+ ...selected,
38
+ ];
39
+ return choices.length > 0
40
+ ? choices
41
+ .map(
42
+ (feature) =>
43
+ feature.selectedName ??
44
+ feature.name ??
45
+ context?.env?.features?.[feature]?.name ??
46
+ feature
47
+ )
48
+ .join(", ")
49
+ : "None";
50
+ },
51
+ ...context?.env?.style,
52
+ },
53
+ });
54
+
55
+ export const theme = createTheme();
56
+ export const warning = createTheme("warn");
package/logo.mjs ADDED
@@ -0,0 +1,3 @@
1
+ import logo from "@lazarv/react-server/bin/logo.mjs";
2
+
3
+ await logo();
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "@lazarv/create-react-server",
3
+ "version": "0.0.0-experimental-d003259-20250211-2495688e",
4
+ "bin": {
5
+ "create-react-server": "index.mjs"
6
+ },
7
+ "type": "module",
8
+ "dependencies": {
9
+ "@inquirer/checkbox": "^4.0.1",
10
+ "@inquirer/confirm": "^5.0.1",
11
+ "@inquirer/core": "^10.0.1",
12
+ "@inquirer/figures": "^1.0.7",
13
+ "@inquirer/input": "^4.0.1",
14
+ "@inquirer/number": "^3.0.1",
15
+ "@inquirer/prompts": "^7.0.0",
16
+ "@inquirer/select": "^4.0.1",
17
+ "ansi-escapes": "^7.0.0",
18
+ "cac": "^6.7.14",
19
+ "fast-glob": "^3.2.12",
20
+ "filesize": "^10.0.12",
21
+ "picocolors": "^1.1.1",
22
+ "prettier": "^3.0.0",
23
+ "ts-morph": "^24.0.0",
24
+ "@lazarv/react-server": "0.0.0-experimental-d003259-20250211-0c721374"
25
+ }
26
+ }
@@ -0,0 +1,50 @@
1
+ import { input } from "@inquirer/prompts";
2
+
3
+ import { theme } from "../lib/theme.mjs";
4
+
5
+ export default [
6
+ (context) => context.features.includes("ts"),
7
+ async (context) => {
8
+ const alias =
9
+ context.env.options.alias ??
10
+ (!context.props.custom ||
11
+ context.env.hasOptions ||
12
+ context.props.preset?.alias
13
+ ? context.props.preset?.alias ?? "~/*"
14
+ : await input(
15
+ {
16
+ message: "TypeScript path alias",
17
+ default: "~/*",
18
+ theme,
19
+ },
20
+ context
21
+ ));
22
+ return {
23
+ ...context,
24
+ props: {
25
+ ...context.props,
26
+ alias,
27
+ },
28
+ partials: {
29
+ ...context.partials,
30
+ "tsconfig.json": {
31
+ ...context.partials["tsconfig.json"],
32
+ merge: [
33
+ ...context.partials["tsconfig.json"].merge,
34
+ { compilerOptions: { paths: { [alias]: ["./*"] } } },
35
+ ],
36
+ },
37
+ "vite.config.ts": {
38
+ ...context.partials["vite.config.ts"],
39
+ merge: [
40
+ ...context.partials["vite.config.ts"].merge,
41
+ `export default defineConfig({ resolve: { alias: { "${alias.slice(
42
+ 0,
43
+ alias.lastIndexOf("/")
44
+ )}/": "/src/" } } })`,
45
+ ],
46
+ },
47
+ },
48
+ };
49
+ },
50
+ ];
@@ -0,0 +1,62 @@
1
+ import { select, Separator } from "@inquirer/prompts";
2
+
3
+ import { theme } from "../lib/theme.mjs";
4
+
5
+ export default [
6
+ (context) => context.props.thirdParty,
7
+ async (context) => {
8
+ const auth = !context.props.custom
9
+ ? "none"
10
+ : await select(
11
+ {
12
+ message: "Authentication provider",
13
+ choices: [
14
+ {
15
+ name: "None",
16
+ value: "none",
17
+ description: "No authentication",
18
+ },
19
+ new Separator(),
20
+ {
21
+ name: "Kinde",
22
+ value: "kinde",
23
+ description: "Add Kinde authentication",
24
+ disabled: "(coming soon)",
25
+ },
26
+ {
27
+ name: "Clerk",
28
+ value: "clerk",
29
+ description: "Add Clerk authentication",
30
+ disabled: "(coming soon)",
31
+ },
32
+ {
33
+ name: "Auth.js",
34
+ value: "authjs",
35
+ description: "Add Auth.js authentication",
36
+ disabled: "(coming soon)",
37
+ },
38
+ {
39
+ name: "Better Auth",
40
+ value: "better-auth",
41
+ description: "Add Better Auth authentication",
42
+ disabled: "(coming soon)",
43
+ },
44
+ {
45
+ name: "Auth0",
46
+ value: "auth0",
47
+ description: "Add Auth0 authentication",
48
+ disabled: "(coming soon)",
49
+ },
50
+ new Separator(),
51
+ ],
52
+ theme,
53
+ },
54
+ context
55
+ );
56
+
57
+ return {
58
+ ...context,
59
+ props: { ...context.props, auth },
60
+ };
61
+ },
62
+ ];
@@ -0,0 +1,56 @@
1
+ import { select, Separator } from "@inquirer/prompts";
2
+
3
+ import { theme } from "../lib/theme.mjs";
4
+
5
+ export default [
6
+ (context) => context.props.thirdParty,
7
+ async (context) => {
8
+ const db = !context.props.custom
9
+ ? "none"
10
+ : await select(
11
+ {
12
+ message: "Database provider",
13
+ choices: [
14
+ {
15
+ name: "None",
16
+ value: "none",
17
+ description: "No database",
18
+ },
19
+ new Separator(),
20
+ {
21
+ name: "Drizzle",
22
+ value: "drizzle",
23
+ description: "Add Drizzle integration",
24
+ disabled: "(coming soon)",
25
+ },
26
+ {
27
+ name: "Prisma",
28
+ value: "prisma",
29
+ description: "Add Prisma integration",
30
+ disabled: "(coming soon)",
31
+ },
32
+ {
33
+ name: "Supabase",
34
+ value: "supabase",
35
+ description: "Add Supabase integration",
36
+ disabled: "(coming soon)",
37
+ },
38
+ {
39
+ name: "Convex",
40
+ value: "convex",
41
+ description: "Add Convex integration",
42
+ disabled: "(coming soon)",
43
+ },
44
+ new Separator(),
45
+ ],
46
+ theme,
47
+ },
48
+ context
49
+ );
50
+
51
+ return {
52
+ ...context,
53
+ props: { ...context.props, db },
54
+ };
55
+ },
56
+ ];
@@ -0,0 +1,151 @@
1
+ import { execSync } from "node:child_process";
2
+ import { readFile } from "node:fs/promises";
3
+ import { join, relative } from "node:path";
4
+
5
+ import { select, Separator } from "@inquirer/prompts";
6
+
7
+ import { theme } from "../lib/theme.mjs";
8
+
9
+ export default async (context) => {
10
+ const adapter =
11
+ context.env.options.deploy ??
12
+ (context.env.hasOptions
13
+ ? "none"
14
+ : await select(
15
+ {
16
+ message: "Deployment adapter",
17
+ choices: [
18
+ {
19
+ name: "None",
20
+ value: "none",
21
+ description: "No deployment adapter",
22
+ },
23
+ new Separator(),
24
+ {
25
+ name: "Docker",
26
+ value: "docker",
27
+ description:
28
+ "Build a Docker image and deploy to a container registry",
29
+ },
30
+ {
31
+ name: "Vercel",
32
+ value: "vercel",
33
+ description: "Deploy to Vercel",
34
+ },
35
+ {
36
+ name: "AWS",
37
+ value: "aws",
38
+ description: "Deploy to AWS Lambda",
39
+ disabled: "(coming soon)",
40
+ },
41
+ ],
42
+ theme,
43
+ },
44
+ context
45
+ ));
46
+
47
+ const partials = {
48
+ ...context.partials,
49
+ };
50
+ const files = context.files;
51
+
52
+ if (adapter === "vercel") {
53
+ partials["package.json"] = {
54
+ ...partials["package.json"],
55
+ merge: [
56
+ ...partials["package.json"].merge,
57
+ {
58
+ devDependencies: {
59
+ "@lazarv/react-server-adapter-vercel": `^${execSync(
60
+ "npm view @lazarv/react-server-adapter-vercel version"
61
+ )
62
+ .toString()
63
+ .trim()}`,
64
+ },
65
+ },
66
+ ],
67
+ };
68
+ partials["react-server.config.json"] = {
69
+ ...partials?.["react-server.config.json"],
70
+ type: "json",
71
+ merge: [
72
+ ...(partials?.["react-server.config.json"]?.merge ?? []),
73
+ {
74
+ adapter: "@lazarv/react-server-adapter-vercel",
75
+ },
76
+ ],
77
+ };
78
+ if (context.features.includes("git")) {
79
+ partials[".gitignore"] = {
80
+ ...partials?.[".gitignore"],
81
+ merge: [
82
+ ...(partials?.[".gitignore"]?.merge ?? []),
83
+ "\n# Vercel\n.vercel\n",
84
+ ],
85
+ };
86
+ }
87
+ }
88
+
89
+ if (adapter === "docker") {
90
+ const merge = [
91
+ await readFile(join(context.env.templateDir, ".dockerignore"), "utf8"),
92
+ ];
93
+ merge.push(
94
+ ...Object.keys(context.partials).map((filename) => `!${filename}`)
95
+ );
96
+ partials[".dockerignore"] = {
97
+ ...partials[".dockerignore"],
98
+ type: "text",
99
+ merge: [...(partials[".dockerignore"]?.merge ?? []), ...merge],
100
+ };
101
+ partials["README.md"] = {
102
+ ...context.partials["README.md"],
103
+ template: `${context.partials["README.md"].template}\n\n${await readFile(join(context.env.templateDir, "README.docker.md"), "utf8")}`,
104
+ };
105
+ }
106
+
107
+ return {
108
+ ...context,
109
+ files,
110
+ props: {
111
+ ...context.props,
112
+ adapter,
113
+ },
114
+ partials,
115
+ };
116
+ };
117
+
118
+ export async function prepare(context) {
119
+ const { adapter, packageManager } = context.props;
120
+ if (adapter === "docker") {
121
+ const dockerfile = join(
122
+ context.env.templateDir,
123
+ `Dockerfile.${packageManager.name}`
124
+ );
125
+ return {
126
+ ...context,
127
+ partials: {
128
+ ...context.partials,
129
+ Dockerfile: {
130
+ type: "text",
131
+ content: await readFile(dockerfile, "utf8"),
132
+ },
133
+ ".dockerignore": {
134
+ ...context.partials[".dockerignore"],
135
+ merge: [
136
+ ...(context.partials[".dockerignore"]?.merge ?? []),
137
+ `!${context.props.packageManager.lock}`,
138
+ ...context.files
139
+ .map((filename) =>
140
+ Array.isArray(filename)
141
+ ? `!${relative(context.env.projectDir, filename[1])}`
142
+ : `!${relative(context.env.templateDir, filename)}`
143
+ )
144
+ .filter((filename) => filename.split("/").length === 1),
145
+ ],
146
+ },
147
+ },
148
+ };
149
+ }
150
+ return context;
151
+ }