create-jant 0.3.10 → 0.3.12

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/dist/index.js CHANGED
@@ -2,13 +2,14 @@
2
2
  import { program } from "commander";
3
3
  import * as p from "@clack/prompts";
4
4
  import chalk from "chalk";
5
+ import { execSync } from "child_process";
5
6
  import crypto from "crypto";
6
7
  import fs from "fs-extra";
7
8
  import path from "path";
8
9
  import { fileURLToPath } from "url";
9
10
  var __filename = fileURLToPath(import.meta.url);
10
11
  var __dirname = path.dirname(__filename);
11
- var CORE_VERSION = "0.3.10";
12
+ var CORE_VERSION = "0.3.12";
12
13
  var TEMPLATE_DIR = fs.existsSync(path.resolve(__dirname, "../template")) ? path.resolve(__dirname, "../template") : path.resolve(__dirname, "../../../templates/jant-site");
13
14
  function isValidProjectName(name) {
14
15
  return /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(name);
@@ -19,6 +20,34 @@ function toValidProjectName(name) {
19
20
  function generateAuthSecret() {
20
21
  return crypto.randomBytes(32).toString("base64");
21
22
  }
23
+ function detectPackageManager() {
24
+ const userAgent = process.env.npm_config_user_agent;
25
+ if (userAgent) {
26
+ const name = userAgent.split("/")[0];
27
+ if (name === "pnpm" || name === "yarn" || name === "npm") {
28
+ return name;
29
+ }
30
+ }
31
+ for (const pm of ["pnpm", "yarn", "npm"]) {
32
+ try {
33
+ execSync(`${pm} --version`, { stdio: "ignore" });
34
+ return pm;
35
+ } catch {
36
+ }
37
+ }
38
+ return "npm";
39
+ }
40
+ function formatRunCmd(pm, script) {
41
+ return pm === "npm" ? `npm run ${script}` : `${pm} ${script}`;
42
+ }
43
+ function runCommand(cmd, cwd) {
44
+ try {
45
+ execSync(cmd, { stdio: "ignore", cwd });
46
+ return true;
47
+ } catch {
48
+ return false;
49
+ }
50
+ }
22
51
  function processMarkers(content, vars) {
23
52
  content = content.replace(
24
53
  /\s*(?:\/\/|#)\s*@create-jant:\s*@remove-start[\s\S]*?(?:\/\/|#)\s*@create-jant:\s*@remove-end\n?/g,
@@ -41,7 +70,7 @@ function processMarkers(content, vars) {
41
70
  return content;
42
71
  }
43
72
  async function copyTemplate(config) {
44
- const { projectName, targetDir } = config;
73
+ const { projectName, targetDir, packageManager } = config;
45
74
  await fs.copy(TEMPLATE_DIR, targetDir, {
46
75
  filter: (src) => {
47
76
  const basename = path.basename(src);
@@ -51,6 +80,10 @@ async function copyTemplate(config) {
51
80
  if (basename === ".swc") return false;
52
81
  if (basename === ".dev.vars") return false;
53
82
  if (basename === "pnpm-lock.yaml") return false;
83
+ if (basename === "yarn.lock") return false;
84
+ if (basename === "package-lock.json") return false;
85
+ if (basename === "bun.lockb") return false;
86
+ if (basename === "pnpm-workspace.yaml") return false;
54
87
  if (basename === "dist") return false;
55
88
  if (basename === "wrangler.demo.toml") return false;
56
89
  if (basename === "reset-demo.sql") return false;
@@ -82,6 +115,19 @@ async function copyTemplate(config) {
82
115
  if (pkg.dependencies?.["@jant/core"] === "workspace:*") {
83
116
  pkg.dependencies["@jant/core"] = `^${CORE_VERSION}`;
84
117
  }
118
+ if (packageManager !== "pnpm") {
119
+ delete pkg.packageManager;
120
+ if (pkg.scripts) {
121
+ for (const [key, value] of Object.entries(pkg.scripts)) {
122
+ if (typeof value === "string") {
123
+ pkg.scripts[key] = value.replace(
124
+ /pnpm (\S+)/g,
125
+ (_, script) => formatRunCmd(packageManager, script)
126
+ );
127
+ }
128
+ }
129
+ }
130
+ }
85
131
  await fs.writeJson(pkgPath, pkg, { spaces: 2 });
86
132
  }
87
133
  const wranglerPath = path.join(targetDir, "wrangler.toml");
@@ -126,11 +172,17 @@ S3_SECRET_ACCESS_KEY=
126
172
  content = processMarkers(content, {});
127
173
  await fs.writeFile(viteConfigPath, content, "utf-8");
128
174
  }
175
+ if (packageManager === "pnpm") {
176
+ const wsSource = path.join(TEMPLATE_DIR, "pnpm-workspace.yaml");
177
+ if (await fs.pathExists(wsSource)) {
178
+ await fs.copy(wsSource, path.join(targetDir, "pnpm-workspace.yaml"));
179
+ }
180
+ }
129
181
  }
130
182
  async function main() {
131
183
  console.log();
132
184
  p.intro(chalk.bgCyan.black(" create-jant "));
133
- program.name("create-jant").description("Create a new Jant project").argument("[project-name]", "Name of the project").option("-y, --yes", "Skip prompts and use defaults").option("--s3", "Use S3-compatible storage instead of Cloudflare R2").parse();
185
+ program.name("create-jant").description("Create a new Jant project").argument("[project-name]", "Name of the project").option("-y, --yes", "Skip prompts and use defaults").option("--s3", "Use S3-compatible storage instead of Cloudflare R2").option("--no-install", "Skip dependency installation").option("--no-git", "Skip git initialization").parse();
134
186
  const args = program.args;
135
187
  const opts = program.opts();
136
188
  let projectName;
@@ -186,9 +238,13 @@ async function main() {
186
238
  await fs.emptyDir(targetDir);
187
239
  }
188
240
  }
241
+ const packageManager = detectPackageManager();
189
242
  const config = {
190
243
  projectName,
191
244
  targetDir,
245
+ packageManager,
246
+ install: opts.install,
247
+ git: opts.git,
192
248
  s3: opts.s3
193
249
  };
194
250
  const spinner2 = p.spinner();
@@ -201,11 +257,36 @@ async function main() {
201
257
  p.log.error(error instanceof Error ? error.message : String(error));
202
258
  process.exit(1);
203
259
  }
260
+ let installOk = false;
261
+ if (config.install) {
262
+ spinner2.start("Installing dependencies...");
263
+ installOk = runCommand(`${packageManager} install`, targetDir);
264
+ if (installOk) {
265
+ spinner2.stop("Dependencies installed.");
266
+ } else {
267
+ spinner2.stop(
268
+ chalk.yellow(
269
+ `Failed to install dependencies. Run ${chalk.bold(`${packageManager} install`)} manually.`
270
+ )
271
+ );
272
+ }
273
+ }
274
+ if (config.git) {
275
+ spinner2.start("Initializing git repository...");
276
+ const gitOk = runCommand("git init", targetDir) && runCommand("git add -A", targetDir) && runCommand('git commit -m "Initial commit"', targetDir);
277
+ if (gitOk) {
278
+ spinner2.stop("Git repository initialized.");
279
+ } else {
280
+ spinner2.stop("Skipped git initialization.");
281
+ }
282
+ }
283
+ const steps = [`cd ${projectName}`];
284
+ if (!config.install || !installOk) {
285
+ steps.push(`${packageManager} install`);
286
+ }
287
+ steps.push(formatRunCmd(packageManager, "dev"));
204
288
  console.log();
205
- p.note(
206
- [`cd ${projectName}`, "pnpm install", "pnpm dev"].join("\n"),
207
- "Next steps"
208
- );
289
+ p.note(steps.join("\n"), "Next steps");
209
290
  p.outro(chalk.green("Happy coding!"));
210
291
  }
211
292
  main().catch((error) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-jant",
3
- "version": "0.3.10",
3
+ "version": "0.3.12",
4
4
  "description": "Create a new Jant project",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,103 +1,77 @@
1
1
  # Jant Site
2
2
 
3
- A personal website/blog powered by [Jant](https://github.com/nicepkg/jant).
3
+ A personal website/blog powered by [Jant](https://github.com/jant-me/jant).
4
4
 
5
5
  ## Getting Started
6
6
 
7
7
  ```bash
8
- # Install dependencies
9
- pnpm install
10
-
11
- # Set up environment variables
12
- cp .dev.vars.example .dev.vars
13
- # Edit .dev.vars and set AUTH_SECRET (32+ random characters)
14
-
15
- # Start development server
16
8
  pnpm dev
17
9
  ```
18
10
 
19
11
  Visit http://localhost:9019 to see your site.
20
12
 
13
+ > Your `.dev.vars` file was automatically generated with a secure `AUTH_SECRET`. See `.dev.vars.example` for all available secret variables.
14
+
21
15
  ## Deploy to Cloudflare
22
16
 
23
- ### 1. Create Cloudflare Resources
17
+ ### 1. Prerequisites
24
18
 
25
- First, make sure you have [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/install-and-update/) installed and logged in:
19
+ Install [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/install-and-update/) and log in:
26
20
 
27
21
  ```bash
28
- # Install wrangler if not already installed
29
- npm install -g wrangler
30
-
31
- # Login to Cloudflare
32
22
  wrangler login
33
23
  ```
34
24
 
35
- Create the required resources:
25
+ ### 2. Create D1 Database
36
26
 
37
27
  ```bash
38
- # Create D1 database
39
- wrangler d1 create my-blog-db
40
- # Note the database_id from the output!
41
-
42
- # Create R2 bucket for media storage
43
- wrangler r2 bucket create my-blog-media
28
+ wrangler d1 create <your-project>-db
29
+ # Copy the database_id from the output!
44
30
  ```
45
31
 
46
- ### 2. Update Configuration
32
+ Replace `<your-project>` with your project name (must match `database_name` in `wrangler.toml`).
47
33
 
48
- Edit `wrangler.toml` with your resource IDs:
34
+ ### 3. Update Configuration
49
35
 
50
- ```toml
51
- name = "my-blog" # Your worker name
36
+ Edit `wrangler.toml`:
52
37
 
53
- [[d1_databases]]
54
- binding = "DB"
55
- database_name = "my-blog-db"
56
- database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" # From step 1
38
+ - Replace `database_id = "local"` with the ID from step 2
39
+ - Set `SITE_URL` to your production URL
57
40
 
58
- [[r2_buckets]]
59
- binding = "R2"
60
- bucket_name = "my-blog-media"
61
- ```
41
+ > R2 bucket is automatically created on first deploy — no manual setup needed.
62
42
 
63
- ### 3. Set Secrets
43
+ ### 4. Set Production Secrets
64
44
 
65
45
  ```bash
66
- # Set authentication secret (use a random 32+ character string)
67
46
  wrangler secret put AUTH_SECRET
68
- # Enter your secret when prompted
69
- ```
70
-
71
- ### 4. Run Migrations
72
-
73
- ```bash
74
- # Apply database migrations
75
- wrangler d1 migrations apply my-blog-db --remote
47
+ # Enter a random 32+ character string when prompted
48
+ # Generate one with: openssl rand -base64 32
76
49
  ```
77
50
 
78
51
  ### 5. Deploy
79
52
 
80
53
  ```bash
54
+ # Apply database migrations to production
55
+ pnpm db:migrate:remote
56
+
81
57
  # Build and deploy
82
58
  pnpm deploy
83
59
  ```
84
60
 
85
- Your site is now live at `https://my-blog.<your-subdomain>.workers.dev`!
61
+ Your site is now live at `https://<your-project>.<your-subdomain>.workers.dev`!
86
62
 
87
63
  ### 6. GitHub Actions (CI/CD)
88
64
 
89
- A workflow file is already included at `.github/workflows/deploy.yml`. You just need to configure secrets.
65
+ A workflow file is included at `.github/workflows/deploy.yml`. You just need to configure secrets.
90
66
 
91
67
  #### Create API Token
92
68
 
93
69
  1. Go to [Cloudflare API Tokens](https://dash.cloudflare.com/profile/api-tokens)
94
- 2. Click **Create Token**
95
- 3. Click **Use template** next to **Edit Cloudflare Workers**
96
- 4. **IMPORTANT: Add D1 permission** (not included in template by default):
97
- - Click **+ Add more**
98
- - Select: **Account** → **D1** → **Edit**
70
+ 2. Click **Create Token** → **Use template** next to **Edit Cloudflare Workers**
71
+ 3. **Add D1 permission** (not in template by default):
72
+ - Click **+ Add more** **Account** **D1** **Edit**
99
73
 
100
- 5. Your permissions should include at minimum:
74
+ Your permissions should include:
101
75
 
102
76
  | Scope | Permission | Access |
103
77
  | ------- | ------------------ | ----------------------------- |
@@ -106,41 +80,30 @@ A workflow file is already included at `.github/workflows/deploy.yml`. You just
106
80
  | Account | **D1** | **Edit** ← Must add manually! |
107
81
  | Zone | Workers Routes | Edit |
108
82
 
109
- 6. **Account Resources** (below permissions list):
110
- - Select **Include** → **Specific account** → Choose your account
111
-
112
- 7. **Zone Resources**:
113
- - Select **Include** → **All zones from an account** → Choose your account
114
-
115
- 8. Click **Continue to summary** → **Create Token**
116
- 9. Copy the token (you won't see it again!)
83
+ 4. Set **Account Resources** **Include** → your account
84
+ 5. Set **Zone Resources** → **Include** → **All zones from an account** → your account
85
+ 6. **Create Token** and copy it
117
86
 
118
87
  #### Add GitHub Secrets
119
88
 
120
- Go to your GitHub repo → **Settings** → **Secrets and variables** → **Actions** → **New repository secret**:
89
+ Go to your repo → **Settings** → **Secrets and variables** → **Actions**:
121
90
 
122
- | Secret Name | Value |
123
- | --------------- | -------------------------------------------------------------------------- |
124
- | `CF_API_TOKEN` | Your API token from above |
125
- | `CF_ACCOUNT_ID` | Your Cloudflare Account ID (find it in dashboard URL or `wrangler whoami`) |
126
- | `AUTH_SECRET` | Random string for authentication (**must be at least 32 characters**) |
91
+ | Secret Name | Value |
92
+ | --------------- | ------------------------------------------------------------------------ |
93
+ | `CF_API_TOKEN` | API token from above |
94
+ | `CF_ACCOUNT_ID` | Your Cloudflare Account ID (found in dashboard URL or `wrangler whoami`) |
95
+ | `AUTH_SECRET` | Random 32+ character string (`openssl rand -base64 32`) |
127
96
 
128
- > **Important**: `AUTH_SECRET` must be at least 32 characters long. You can generate one with:
129
- >
130
- > ```bash
131
- > openssl rand -base64 32
132
- > ```
133
-
134
- That's it! Push to `main` branch to trigger deployment.
97
+ Push to `main` to trigger deployment.
135
98
 
136
99
  #### Using Environments (Optional)
137
100
 
138
- If you want separate staging/production environments, update `.github/workflows/deploy.yml`:
101
+ For separate staging/production, update `.github/workflows/deploy.yml`:
139
102
 
140
103
  ```yaml
141
104
  jobs:
142
105
  deploy:
143
- uses: nicepkg/jant/.github/workflows/deploy.yml@v1
106
+ uses: jant-me/jant/.github/workflows/deploy.yml@v1
144
107
  with:
145
108
  environment: production # Uses [env.production] in wrangler.toml
146
109
  secrets:
@@ -151,35 +114,29 @@ jobs:
151
114
 
152
115
  ### 7. Custom Domain (Optional)
153
116
 
154
- To use your own domain:
155
-
156
- 1. Go to [Cloudflare Dashboard](https://dash.cloudflare.com) > Workers & Pages
157
- 2. Select your worker > Settings > Triggers
158
- 3. Click "Add Custom Domain"
159
- 4. Enter your domain (e.g., `blog.example.com`)
117
+ 1. Go to [Cloudflare Dashboard](https://dash.cloudflare.com) → Workers & Pages
118
+ 2. Select your worker → Settings → Triggers
119
+ 3. Click **Add Custom Domain** and enter your domain
160
120
 
161
121
  ## Commands
162
122
 
163
- | Command | Description |
164
- | ---------------- | ------------------------------ |
165
- | `pnpm dev` | Start development server |
166
- | `pnpm build` | Build for production |
167
- | `pnpm deploy` | Build and deploy to Cloudflare |
168
- | `pnpm preview` | Preview production build |
169
- | `pnpm typecheck` | Run TypeScript checks |
123
+ | Command | Description |
124
+ | ------------------------ | ---------------------------------- |
125
+ | `pnpm dev` | Start development server |
126
+ | `pnpm build` | Build for production |
127
+ | `pnpm deploy` | Build and deploy to Cloudflare |
128
+ | `pnpm preview` | Preview production build |
129
+ | `pnpm typecheck` | Run TypeScript checks |
130
+ | `pnpm db:migrate:remote` | Apply database migrations (remote) |
170
131
 
171
132
  ## Environment Variables
172
133
 
173
- Core environment variables:
174
-
175
134
  | Variable | Description | Location |
176
135
  | ------------- | ----------------------------------------- | ---------------- |
177
136
  | `AUTH_SECRET` | Secret key for authentication (32+ chars) | `.dev.vars` file |
178
137
  | `SITE_URL` | Your site's public URL | `wrangler.toml` |
179
138
 
180
- For a complete list of all available environment variables (site configuration, R2 storage, image optimization, demo mode, etc.), see:
181
-
182
- **[📖 Full Configuration Guide](https://github.com/nicepkg/jant/blob/main/docs/configuration.md)**
139
+ For all available variables (site name, language, R2 storage, image optimization, S3, demo mode, etc.), see the **[Configuration Guide](https://github.com/jant-me/jant/blob/main/docs/configuration.md)**.
183
140
 
184
141
  ## Customization
185
142
 
@@ -247,33 +204,23 @@ export default createApp({
247
204
 
248
205
  ## Updating
249
206
 
250
- 1. Update the `@jant/core` package:
251
-
252
207
  ```bash
208
+ # Update @jant/core
253
209
  pnpm update @jant/core
254
- ```
255
-
256
- 2. Apply database migrations locally (this happens automatically when you run `pnpm dev`):
257
210
 
258
- ```bash
211
+ # Start dev server (auto-applies migrations locally)
259
212
  pnpm dev
260
- ```
261
213
 
262
- 3. Before deploying to production, apply migrations to your remote D1 database:
263
-
264
- ```bash
214
+ # Before deploying: apply migrations to production
265
215
  pnpm db:migrate:remote
266
- ```
267
-
268
- 4. Deploy:
269
216
 
270
- ```bash
217
+ # Deploy
271
218
  pnpm deploy
272
219
  ```
273
220
 
274
- > **Note:** New versions of `@jant/core` may include database migrations. Always run `pnpm db:migrate:remote` before deploying after an update. Check the [release notes](https://github.com/nicepkg/jant/releases) for any breaking changes.
221
+ > New versions of `@jant/core` may include database migrations. Always run `pnpm db:migrate:remote` before deploying after an update. Check the [release notes](https://github.com/jant-me/jant/releases) for any breaking changes.
275
222
 
276
223
  ## Documentation
277
224
 
278
225
  - [Jant Documentation](https://jant.me/docs)
279
- - [GitHub Repository](https://github.com/nicepkg/jant)
226
+ - [GitHub Repository](https://github.com/jant-me/jant)
@@ -16,7 +16,7 @@ on:
16
16
 
17
17
  jobs:
18
18
  deploy:
19
- uses: nicepkg/jant/.github/workflows/deploy.yml@v1
19
+ uses: jant-me/jant/.github/workflows/deploy.yml@v1
20
20
  secrets:
21
21
  CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
22
22
  CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
@@ -3,6 +3,7 @@ node_modules/
3
3
 
4
4
  # Build outputs
5
5
  dist/
6
+ .swc/
6
7
 
7
8
  # Cloudflare
8
9
  .wrangler/
@@ -44,7 +44,7 @@ pnpm dev
44
44
  </code></pre>
45
45
  <p>Visit the <a href="/dash">dashboard</a> to create your own posts!</p>',NULL,NULL,NULL,NULL,NULL,NULL,1770689095,1770689095,1770689095);
46
46
  INSERT INTO posts VALUES(2,'note','quiet',NULL,NULL,'This is a demo note. Notes are short posts without titles, perfect for quick thoughts and updates.','<p>This is a demo note. Notes are short posts without titles, perfect for quick thoughts and updates.</p>',NULL,NULL,NULL,NULL,NULL,NULL,1770685495,1770685495,1770685495);
47
- INSERT INTO posts VALUES(3,'link','quiet','Jant on GitHub',NULL,'Check out the source code and documentation for Jant.','<p>Check out the source code and documentation for Jant.</p>','https://github.com/nicepkg/jant','GitHub','github.com',NULL,NULL,NULL,1770681895,1770681895,1770681895);
47
+ INSERT INTO posts VALUES(3,'link','quiet','Jant on GitHub',NULL,'Check out the source code and documentation for Jant.','<p>Check out the source code and documentation for Jant.</p>','https://github.com/jant-me/jant','GitHub','github.com',NULL,NULL,NULL,1770681895,1770681895,1770681895);
48
48
  INSERT INTO posts VALUES(4,'quote','quiet',NULL,NULL,'The best way to predict the future is to invent it.','<p>The best way to predict the future is to invent it.</p>',NULL,'Alan Kay',NULL,NULL,NULL,NULL,1770678295,1770678295,1770678295);
49
49
  INSERT INTO posts VALUES(5,'image','quiet',NULL,NULL,'Image 1','<p>Image 1</p>
50
50
  ',NULL,NULL,NULL,NULL,NULL,NULL,1770758516,1770758516,1770758516);
@@ -42,11 +42,18 @@ R2_PUBLIC_URL = "https://demo-media.jant.me" # @create-jant: @remove
42
42
  # Optional: S3-compatible storage (alternative to R2)
43
43
  # Set STORAGE_DRIVER = "s3" and configure the options below.
44
44
  # When using S3, the [[r2_buckets]] section can be removed.
45
+ # STORAGE_DRIVER = "s3"
46
+ # S3_ENDPOINT = "https://s3.example.com"
47
+ # S3_BUCKET = "my-bucket"
48
+ # S3_REGION = "us-east-1"
49
+ # S3_PUBLIC_URL = "https://cdn.example.com"
50
+ # @create-jant: @remove-start
45
51
  STORAGE_DRIVER = "s3"
46
52
  S3_ENDPOINT = "https://s3.us-east-005.backblazeb2.com"
47
53
  S3_BUCKET = "jant-media"
48
54
  S3_REGION = "us-east-005"
49
55
  S3_PUBLIC_URL = "https://files.owenyoung.com/file/jant-media"
56
+ # @create-jant: @remove-end
50
57
 
51
58
  [[d1_databases]]
52
59
  binding = "DB"