create-oxom-app 0.1.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.
- package/README.md +27 -0
- package/bin/create-oxom-app.js +129 -0
- package/package.json +25 -0
package/README.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# create-oxom-app
|
|
2
|
+
|
|
3
|
+
Scaffold a new [plattform](https://github.com/oxom-de/plattform) workspace in seconds.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npx create-oxom-app my-workspace
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Or interactively:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx create-oxom-app
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## What it does
|
|
16
|
+
|
|
17
|
+
1. Clones the latest `plattform` template from GitHub
|
|
18
|
+
2. Asks for a project name and brand name
|
|
19
|
+
3. Writes a `.env.local` with your brand name pre-filled
|
|
20
|
+
4. Runs `pnpm install` (falls back to `bun` or `npm`)
|
|
21
|
+
5. Prints the next steps
|
|
22
|
+
|
|
23
|
+
## Requirements
|
|
24
|
+
|
|
25
|
+
- Node.js 20+
|
|
26
|
+
- git
|
|
27
|
+
- pnpm (recommended), bun, or npm
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { execSync } from "node:child_process";
|
|
4
|
+
import { createInterface } from "node:readline";
|
|
5
|
+
import { existsSync, rmSync, readFileSync, writeFileSync, copyFileSync } from "node:fs";
|
|
6
|
+
import { resolve, join } from "node:path";
|
|
7
|
+
|
|
8
|
+
// ── Config ─────────────────────────────────────────────────────────────────
|
|
9
|
+
|
|
10
|
+
const REPO_URL = "https://github.com/oxom-de/plattform.git";
|
|
11
|
+
const REPO_DISPLAY = "github.com/oxom-de/plattform";
|
|
12
|
+
|
|
13
|
+
// ── Helpers ────────────────────────────────────────────────────────────────
|
|
14
|
+
|
|
15
|
+
const cyan = (s) => `\x1b[36m${s}\x1b[0m`;
|
|
16
|
+
const green = (s) => `\x1b[32m${s}\x1b[0m`;
|
|
17
|
+
const bold = (s) => `\x1b[1m${s}\x1b[0m`;
|
|
18
|
+
const dim = (s) => `\x1b[2m${s}\x1b[0m`;
|
|
19
|
+
|
|
20
|
+
function prompt(rl, question) {
|
|
21
|
+
return new Promise((resolve) => rl.question(question, resolve));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function run(cmd, cwd) {
|
|
25
|
+
execSync(cmd, { cwd, stdio: "inherit" });
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function hasBin(bin) {
|
|
29
|
+
try {
|
|
30
|
+
execSync(`which ${bin}`, { stdio: "ignore" });
|
|
31
|
+
return true;
|
|
32
|
+
} catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// ── Main ───────────────────────────────────────────────────────────────────
|
|
38
|
+
|
|
39
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
40
|
+
|
|
41
|
+
console.log(`\n${bold("create-oxom-app")} ${dim(`→ ${REPO_DISPLAY}`)}\n`);
|
|
42
|
+
|
|
43
|
+
// 1. Project name
|
|
44
|
+
let projectName = process.argv[2]?.trim();
|
|
45
|
+
if (!projectName) {
|
|
46
|
+
projectName = (await prompt(rl, `Project name ${dim("(my-workspace)")} `)).trim() || "my-workspace";
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const projectDir = resolve(process.cwd(), projectName);
|
|
50
|
+
if (existsSync(projectDir)) {
|
|
51
|
+
console.error(`\nDirectory "${projectName}" already exists. Choose a different name.\n`);
|
|
52
|
+
rl.close();
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 2. Brand name
|
|
57
|
+
const brandName = (await prompt(rl, `Brand name ${dim(`(${projectName})`)} `)).trim() || projectName;
|
|
58
|
+
|
|
59
|
+
rl.close();
|
|
60
|
+
|
|
61
|
+
// 3. Clone
|
|
62
|
+
console.log(`\n${cyan("→")} Cloning template from ${REPO_DISPLAY}…`);
|
|
63
|
+
try {
|
|
64
|
+
run(`git clone --depth=1 ${REPO_URL} "${projectName}"`, process.cwd());
|
|
65
|
+
} catch {
|
|
66
|
+
console.error("\nFailed to clone repository. Make sure git is installed and you have internet access.\n");
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Remove git history so the user starts fresh
|
|
71
|
+
rmSync(join(projectDir, ".git"), { recursive: true, force: true });
|
|
72
|
+
|
|
73
|
+
// 4. Patch package.json name
|
|
74
|
+
const pkgPath = join(projectDir, "package.json");
|
|
75
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
76
|
+
pkg.name = projectName;
|
|
77
|
+
writeFileSync(pkgPath, JSON.stringify(pkg, null, "\t") + "\n");
|
|
78
|
+
|
|
79
|
+
// 5. Write .env.local from example
|
|
80
|
+
const envExamplePath = join(projectDir, ".env.local.example");
|
|
81
|
+
const envLocalPath = join(projectDir, ".env.local");
|
|
82
|
+
|
|
83
|
+
if (existsSync(envExamplePath)) {
|
|
84
|
+
let env = readFileSync(envExamplePath, "utf8");
|
|
85
|
+
// Patch brand name
|
|
86
|
+
env = env.replace(
|
|
87
|
+
/^NEXT_PUBLIC_BRAND_NAME=.*/m,
|
|
88
|
+
`NEXT_PUBLIC_BRAND_NAME=${brandName}`,
|
|
89
|
+
);
|
|
90
|
+
writeFileSync(envLocalPath, env);
|
|
91
|
+
} else {
|
|
92
|
+
writeFileSync(
|
|
93
|
+
envLocalPath,
|
|
94
|
+
`NEXT_PUBLIC_BRAND_NAME=${brandName}\nNEXT_PUBLIC_APP_URL=http://localhost:3000\n`,
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// 6. Install dependencies
|
|
99
|
+
const pm = hasBin("pnpm") ? "pnpm" : hasBin("bun") ? "bun" : "npm";
|
|
100
|
+
console.log(`\n${cyan("→")} Installing dependencies with ${pm}…\n`);
|
|
101
|
+
try {
|
|
102
|
+
run(`${pm} install`, projectDir);
|
|
103
|
+
} catch {
|
|
104
|
+
console.warn("\nDependency install failed — run it manually inside the project directory.\n");
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// 7. Done
|
|
108
|
+
console.log(`
|
|
109
|
+
${green("✓")} ${bold(projectName)} is ready.
|
|
110
|
+
|
|
111
|
+
${bold("Next steps:")}
|
|
112
|
+
|
|
113
|
+
${cyan(`cd ${projectName}`)}
|
|
114
|
+
${dim("# Fill in your credentials:")}
|
|
115
|
+
${cyan("open .env.local")}
|
|
116
|
+
${dim("# Apply database migrations to your Supabase project:")}
|
|
117
|
+
${dim("# → supabase/migrations/")}
|
|
118
|
+
${cyan(`${pm} dev`)}
|
|
119
|
+
|
|
120
|
+
${bold("Services you need:")}
|
|
121
|
+
|
|
122
|
+
Clerk https://clerk.com
|
|
123
|
+
Supabase https://supabase.com
|
|
124
|
+
Liveblocks https://liveblocks.io
|
|
125
|
+
Dub https://dub.co ${dim("(optional — link shortening)")}
|
|
126
|
+
R2 / S3 ${dim("(optional — configure per workspace in Settings → Drive)")}
|
|
127
|
+
|
|
128
|
+
${dim(`Docs: ${REPO_DISPLAY}#readme`)}
|
|
129
|
+
`);
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-oxom-app",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Create a new plattform workspace app",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"create-oxom-app": "./bin/create-oxom-app.js"
|
|
9
|
+
},
|
|
10
|
+
"engines": {
|
|
11
|
+
"node": ">=20"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"create-app",
|
|
15
|
+
"plattform",
|
|
16
|
+
"workspace",
|
|
17
|
+
"nextjs",
|
|
18
|
+
"clerk",
|
|
19
|
+
"supabase"
|
|
20
|
+
],
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/oxom-de/create-oxom-app"
|
|
24
|
+
}
|
|
25
|
+
}
|