cosmolo 0.3.9 → 0.5.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 +161 -5
- package/dist/cli/index.js +9 -1
- package/dist/cli/init.js +173 -21
- package/dist/cli/migrate/drizzle-setup.d.ts +2 -0
- package/dist/cli/migrate/drizzle-setup.js +411 -0
- package/dist/cli/migrate/schema.d.ts +12 -0
- package/dist/cli/migrate/schema.js +56 -0
- package/dist/cli/migrate/sql-execute.d.ts +2 -0
- package/dist/cli/migrate/sql-execute.js +67 -0
- package/dist/cli/migrate/sql-export.d.ts +4 -0
- package/dist/cli/migrate/sql-export.js +76 -0
- package/dist/cli/migrate.d.ts +1 -0
- package/dist/cli/migrate.js +54 -0
- package/dist/cli/setup/r2.d.ts +1 -0
- package/dist/cli/setup/r2.js +90 -0
- package/dist/markdown.js +7 -3
- package/dist/types.d.ts +0 -3
- package/package.json +2 -2
- package/templates/shared/config/site.json +1 -2
package/README.md
CHANGED
|
@@ -24,6 +24,7 @@ a canonical "just add Markdown and go" story without asking you to leave.
|
|
|
24
24
|
| Component in Markdown | Yes (.svx) | Yes (.mdx) | Yes | No |
|
|
25
25
|
| Config-driven categories | Yes | No | No | No |
|
|
26
26
|
| Headless CMS (JSON API) | Yes | Manual | Manual | Manual |
|
|
27
|
+
| DB migration path | `migrate:db` | No | No | Manual |
|
|
27
28
|
| Learning curve | SvelteKit only | Astro concepts | Vue + Nuxt | SvelteKit only |
|
|
28
29
|
|
|
29
30
|
**Core principles:**
|
|
@@ -53,7 +54,7 @@ bun generate:article
|
|
|
53
54
|
bun dev
|
|
54
55
|
```
|
|
55
56
|
|
|
56
|
-
`cosmolo init` asks two questions — which mode (
|
|
57
|
+
`cosmolo init` asks two questions — which mode (Full or Slim) and which adapter (SSG, Cloudflare, or Serverless) — then copies the appropriate route files into your project.
|
|
57
58
|
|
|
58
59
|
---
|
|
59
60
|
|
|
@@ -272,6 +273,160 @@ Prompts for key (slug), label, and description. Appends the new entry to `config
|
|
|
272
273
|
|
|
273
274
|
---
|
|
274
275
|
|
|
276
|
+
## Cloudflare
|
|
277
|
+
|
|
278
|
+
Cosmolo works with any SvelteKit-compatible deployment platform, but it is purpose-built
|
|
279
|
+
around the Cloudflare stack. SvelteKit and Cloudflare Workers are an unusually good fit —
|
|
280
|
+
edge-native rendering, zero cold starts, globally distributed infrastructure, and a generous
|
|
281
|
+
free tier. Cosmolo's CLI removes the usual setup friction so you can go from `init` to
|
|
282
|
+
deployed in minutes.
|
|
283
|
+
|
|
284
|
+
### One-command Cloudflare setup
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
bunx cosmolo init # choose "Cloudflare" when prompted for adapter
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
This single command generates everything needed to deploy:
|
|
291
|
+
|
|
292
|
+
| Generated file | Purpose |
|
|
293
|
+
|---|---|
|
|
294
|
+
| `svelte.config.js` | Pre-configured with `adapter-cloudflare` |
|
|
295
|
+
| `wrangler.toml` | Project name, `nodejs_compat`, D1 template commented out |
|
|
296
|
+
| `src/app.d.ts` | `App.Platform` with `Env`, `CfProperties`, `ExecutionContext` |
|
|
297
|
+
| `.github/workflows/deploy.yml` | Optional — push-to-`main` deploy via `wrangler-action` |
|
|
298
|
+
|
|
299
|
+
After init, two commands to go live:
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
bun install && bun add -D @sveltejs/adapter-cloudflare @cloudflare/workers-types
|
|
303
|
+
bun run deploy # bun run build + wrangler pages deploy
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
If you opted in to GitHub Actions during init, pushing to `main` triggers the deploy automatically.
|
|
307
|
+
|
|
308
|
+
### Cloudflare services
|
|
309
|
+
|
|
310
|
+
| Command | What it sets up |
|
|
311
|
+
|---|---|
|
|
312
|
+
| `cosmolo migrate:db` → option 3 | **D1** — Drizzle schema, CRUD helpers (`getArticlesByCategory`, `getArticlesByTag`, …), D1-backed `+page.server.ts` route files |
|
|
313
|
+
| `cosmolo setup:r2` | **R2** — `wrangler.toml` binding, `src/lib/r2.ts` helper, `/assets/[...key]` edge serving route |
|
|
314
|
+
|
|
315
|
+
Each command is self-contained — run only the ones you need.
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## Database Migration
|
|
320
|
+
|
|
321
|
+
When a file-based Cosmolo site outgrows Markdown — multiple writers, mobile editing,
|
|
322
|
+
a growing team — `migrate:db` converts your content to a database without rewriting
|
|
323
|
+
your application code.
|
|
324
|
+
|
|
325
|
+
DB support is optional. File-based sites continue to work exactly as before.
|
|
326
|
+
Migration is a one-time operation when you're ready to scale.
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
bunx cosmolo migrate:db
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
The command is interactive and offers three paths:
|
|
333
|
+
|
|
334
|
+
| Option | Description |
|
|
335
|
+
|---|---|
|
|
336
|
+
| **1 — Export SQL files** | Generates `cosmolo-migration/*.sql` (CREATE TABLE + INSERT for all articles and categories). Works with any relational database. |
|
|
337
|
+
| **2 — Execute directly** | Executes the same SQL against a local SQLite database. Set `DATABASE_URL=./mysite.db` before running. |
|
|
338
|
+
| **3 — Drizzle + Cloudflare D1** | Full setup: generates Drizzle schema, CRUD helpers, `wrangler.toml` D1 binding, and `drizzle.config.ts`. Runs preflight checks before writing anything. |
|
|
339
|
+
|
|
340
|
+
### What gets migrated
|
|
341
|
+
|
|
342
|
+
- **Articles** — all frontmatter fields plus the raw Markdown body. Subdirectory-organized files (e.g. `articles/2024/post.md`) are handled automatically; the slug becomes `2024/post`.
|
|
343
|
+
- **Categories** — from `config/categories.json`
|
|
344
|
+
- **Draft articles** — included in the DB with `draft = 1`; the generated `getArticles()` helper filters them out automatically
|
|
345
|
+
|
|
346
|
+
### Option 3 — Drizzle + Cloudflare D1
|
|
347
|
+
|
|
348
|
+
After a preflight check (drizzle installed, wrangler.toml, table conflicts), the following files are generated:
|
|
349
|
+
|
|
350
|
+
```
|
|
351
|
+
drizzle/schema.ts ← Drizzle schema for articles and categories tables
|
|
352
|
+
src/lib/db/articles.ts ← getArticles, getArticlesByCategory, getArticlesByTag,
|
|
353
|
+
getArticle, parseArticle, createArticle, updateArticle, deleteArticle
|
|
354
|
+
src/lib/db/categories.ts ← getCategories, getCategory, createCategory, updateCategory, deleteCategory
|
|
355
|
+
wrangler.toml ← [[d1_databases]] binding added (merged if file exists)
|
|
356
|
+
drizzle.config.ts ← drizzle-kit config (dialect: sqlite)
|
|
357
|
+
.dev.vars.example ← Cloudflare environment variable reference
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
Optionally (prompted during setup), the existing `+page.server.ts` route files are replaced with D1-backed versions that read from `platform.env.DB` instead of the Cosmolo virtual module:
|
|
361
|
+
|
|
362
|
+
```
|
|
363
|
+
src/routes/+page.server.ts ← Home page — getArticles + getCategories from D1
|
|
364
|
+
src/routes/articles/[slug]/+page.server.ts ← Article — getArticle from D1, Markdown rendered with marked
|
|
365
|
+
src/routes/categories/[slug]/+page.server.ts ← Category — getArticlesByCategory from D1
|
|
366
|
+
src/routes/tags/[tag]/+page.server.ts ← Tag — getArticlesByTag from D1 (json_each query)
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
The command prints step-by-step instructions after generation:
|
|
370
|
+
1. `bunx wrangler d1 create <db-name>` and copy the `database_id` into `wrangler.toml`
|
|
371
|
+
2. `bunx drizzle-kit generate` to create SQL migration files
|
|
372
|
+
3. `bunx wrangler d1 migrations apply <db-name> --local` to apply locally
|
|
373
|
+
4. Run Option 1 to export seed SQL, then `wrangler d1 execute` to import your articles
|
|
374
|
+
5. `bun add -d @cloudflare/workers-types` for TypeScript support
|
|
375
|
+
6. Add `interface Platform { env: { DB: D1Database } }` to `src/app.d.ts`
|
|
376
|
+
|
|
377
|
+
### SSR requirement
|
|
378
|
+
|
|
379
|
+
DB-backed content requires a server-capable adapter. Content in D1 is resolved at
|
|
380
|
+
request time, so `adapter-static` (SSG) is not compatible.
|
|
381
|
+
|
|
382
|
+
Switch to `adapter-cloudflare` for Cloudflare Pages, or `adapter-node` for a
|
|
383
|
+
self-hosted server:
|
|
384
|
+
|
|
385
|
+
```diff
|
|
386
|
+
- import adapter from '@sveltejs/adapter-static';
|
|
387
|
+
+ import adapter from '@sveltejs/adapter-cloudflare';
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
The upside: content edits take effect immediately — no rebuild or redeploy needed.
|
|
391
|
+
|
|
392
|
+
---
|
|
393
|
+
|
|
394
|
+
## R2 Asset Storage
|
|
395
|
+
|
|
396
|
+
Add Cloudflare R2 object storage for article images and other binary assets:
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
bunx cosmolo setup:r2
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
The command asks for a bucket name and binding name, then generates:
|
|
403
|
+
|
|
404
|
+
```
|
|
405
|
+
src/lib/r2.ts ← getR2Asset(bucket, key) helper
|
|
406
|
+
src/routes/assets/[...key]/+server.ts ← Edge route — serves files directly from R2
|
|
407
|
+
wrangler.toml ← [[r2_buckets]] binding appended
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
After setup:
|
|
411
|
+
|
|
412
|
+
```bash
|
|
413
|
+
# 1. Create the bucket
|
|
414
|
+
bunx wrangler r2 bucket create <bucket-name>
|
|
415
|
+
|
|
416
|
+
# 2. Upload an asset
|
|
417
|
+
bunx wrangler r2 object put <bucket-name>/images/photo.jpg --file ./static/images/photo.jpg
|
|
418
|
+
|
|
419
|
+
# 3. Reference it in templates as /assets/images/photo.jpg
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
Add the binding type to `src/app.d.ts` (one line):
|
|
423
|
+
|
|
424
|
+
```ts
|
|
425
|
+
interface Platform { env: { ASSETS: R2Bucket } }
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
---
|
|
429
|
+
|
|
275
430
|
## Headless CMS
|
|
276
431
|
|
|
277
432
|
Cosmolo can expose your content as static JSON endpoints, making it usable as a
|
|
@@ -325,7 +480,7 @@ bun add -D vite @sveltejs/kit
|
|
|
325
480
|
**1. Create `cosmolo.config.ts`** in your project root
|
|
326
481
|
|
|
327
482
|
```typescript
|
|
328
|
-
import { resolveConfig } from 'cosmolo';
|
|
483
|
+
import { resolveConfig } from 'cosmolo/plugin';
|
|
329
484
|
|
|
330
485
|
export default resolveConfig({
|
|
331
486
|
articlesDir: 'src/content/articles', // default
|
|
@@ -373,10 +528,11 @@ The command asks two questions:
|
|
|
373
528
|
|
|
374
529
|
**Adapter**
|
|
375
530
|
|
|
376
|
-
| Adapter |
|
|
531
|
+
| Adapter | Generated files |
|
|
377
532
|
|---|---|
|
|
378
|
-
| **SSG** (`adapter-static`) |
|
|
379
|
-
| **
|
|
533
|
+
| **SSG** (`adapter-static`) | `svelte.config.js` (adapter-static) + `src/routes/+layout.ts` (`prerender = true`) |
|
|
534
|
+
| **Cloudflare** (`adapter-cloudflare`) | `svelte.config.js` (adapter-cloudflare) + `wrangler.toml` + `src/app.d.ts` (`Platform` type). Optionally `.github/workflows/deploy.yml`. |
|
|
535
|
+
| **Serverless** | No extra files — bring your own adapter (Vercel, Node, etc.) |
|
|
380
536
|
|
|
381
537
|
If any target file already exists, the command lists every conflict and exits without
|
|
382
538
|
writing anything.
|
package/dist/cli/index.js
CHANGED
|
@@ -7,14 +7,22 @@ switch (cmd) {
|
|
|
7
7
|
case 'generate':
|
|
8
8
|
await (await import('./generate.js')).main();
|
|
9
9
|
break;
|
|
10
|
+
case 'migrate:db':
|
|
11
|
+
await (await import('./migrate.js')).main();
|
|
12
|
+
break;
|
|
13
|
+
case 'setup:r2':
|
|
14
|
+
await (await import('./setup/r2.js')).main();
|
|
15
|
+
break;
|
|
10
16
|
default: {
|
|
11
17
|
const isUnknown = Boolean(cmd);
|
|
12
18
|
if (isUnknown)
|
|
13
19
|
console.error(`Unknown command: ${cmd}\n`);
|
|
14
20
|
console.log('Usage: cosmolo <command>\n');
|
|
15
21
|
console.log('Commands:');
|
|
16
|
-
console.log(' init Scaffold routes into
|
|
22
|
+
console.log(' init Scaffold routes and config into a SvelteKit project');
|
|
17
23
|
console.log(' generate [article|page|category] Create content files');
|
|
24
|
+
console.log(' migrate:db Migrate file-based content to a database (D1)');
|
|
25
|
+
console.log(' setup:r2 Add Cloudflare R2 bucket for asset storage');
|
|
18
26
|
process.exit(isUnknown ? 1 : 0);
|
|
19
27
|
}
|
|
20
28
|
}
|
package/dist/cli/init.js
CHANGED
|
@@ -36,7 +36,21 @@ function destPath(relativePath, projectRoot) {
|
|
|
36
36
|
.replace(/^lib\//, 'src/lib/');
|
|
37
37
|
return path.join(projectRoot, mapped);
|
|
38
38
|
}
|
|
39
|
-
function
|
|
39
|
+
function readProjectName(projectRoot) {
|
|
40
|
+
const pkgPath = path.join(projectRoot, 'package.json');
|
|
41
|
+
if (fs.existsSync(pkgPath)) {
|
|
42
|
+
try {
|
|
43
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
44
|
+
if (typeof pkg.name === 'string' && pkg.name)
|
|
45
|
+
return pkg.name;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// fall through
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return 'my-cosmolo-site';
|
|
52
|
+
}
|
|
53
|
+
function injectPackageScripts(projectRoot, adapter) {
|
|
40
54
|
const pkgPath = path.join(projectRoot, 'package.json');
|
|
41
55
|
if (!fs.existsSync(pkgPath))
|
|
42
56
|
return;
|
|
@@ -49,6 +63,9 @@ function injectPackageScripts(projectRoot) {
|
|
|
49
63
|
'generate:page': 'cosmolo generate page',
|
|
50
64
|
'generate:category': 'cosmolo generate category',
|
|
51
65
|
};
|
|
66
|
+
if (adapter === 'cloudflare') {
|
|
67
|
+
scripts['deploy'] = 'bun run build && bunx wrangler pages deploy .svelte-kit/cloudflare';
|
|
68
|
+
}
|
|
52
69
|
for (const [key, val] of Object.entries(scripts)) {
|
|
53
70
|
if (!pkg.scripts[key]) {
|
|
54
71
|
pkg.scripts[key] = val;
|
|
@@ -64,6 +81,40 @@ function injectPackageScripts(projectRoot) {
|
|
|
64
81
|
console.log(' updated package.json (added cosmolo dependency + generate:* scripts)');
|
|
65
82
|
}
|
|
66
83
|
}
|
|
84
|
+
function svelteConfigContent(adapter) {
|
|
85
|
+
const pkg = adapter === 'ssg' ? '@sveltejs/adapter-static' : '@sveltejs/adapter-cloudflare';
|
|
86
|
+
return (`import adapter from '${pkg}';\n` +
|
|
87
|
+
`import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';\n\n` +
|
|
88
|
+
`/** @type {import('@sveltejs/kit').Config} */\n` +
|
|
89
|
+
`const config = {\n` +
|
|
90
|
+
`\tpreprocess: vitePreprocess(),\n` +
|
|
91
|
+
`\tkit: {\n` +
|
|
92
|
+
`\t\tadapter: adapter(),\n` +
|
|
93
|
+
`\t},\n` +
|
|
94
|
+
`};\n\n` +
|
|
95
|
+
`export default config;\n`);
|
|
96
|
+
}
|
|
97
|
+
function githubActionsContent(projectName) {
|
|
98
|
+
return (`name: Deploy to Cloudflare Pages\n\n` +
|
|
99
|
+
`on:\n` +
|
|
100
|
+
` push:\n` +
|
|
101
|
+
` branches: [main]\n\n` +
|
|
102
|
+
`jobs:\n` +
|
|
103
|
+
` deploy:\n` +
|
|
104
|
+
` runs-on: ubuntu-latest\n` +
|
|
105
|
+
` permissions:\n` +
|
|
106
|
+
` contents: read\n` +
|
|
107
|
+
` deployments: write\n` +
|
|
108
|
+
` steps:\n` +
|
|
109
|
+
` - uses: actions/checkout@v4\n` +
|
|
110
|
+
` - uses: oven-sh/setup-bun@v2\n` +
|
|
111
|
+
` - run: bun install --frozen-lockfile\n` +
|
|
112
|
+
` - run: bun run build\n` +
|
|
113
|
+
` - uses: cloudflare/wrangler-action@v3\n` +
|
|
114
|
+
` with:\n` +
|
|
115
|
+
` apiToken: \${{ secrets.CF_API_TOKEN }}\n` +
|
|
116
|
+
` command: pages deploy .svelte-kit/cloudflare --project-name=${projectName}\n`);
|
|
117
|
+
}
|
|
67
118
|
// ─── main ─────────────────────────────────────────────────────────────────────
|
|
68
119
|
export async function main() {
|
|
69
120
|
const PROJECT_ROOT = process.cwd();
|
|
@@ -82,15 +133,16 @@ export async function main() {
|
|
|
82
133
|
const mode = modeRaw === '1' ? 'full' : 'slim';
|
|
83
134
|
// ── Adapter selection ───────────────────────────────────────────────────
|
|
84
135
|
console.log('\nChoose your deployment adapter:\n');
|
|
85
|
-
console.log(' 1) SSG
|
|
86
|
-
console.log(' 2)
|
|
136
|
+
console.log(' 1) SSG — @sveltejs/adapter-static (GitHub Pages, Cloudflare Pages static, etc.)');
|
|
137
|
+
console.log(' 2) Cloudflare — @sveltejs/adapter-cloudflare (Workers / Pages SSR)');
|
|
138
|
+
console.log(' 3) Serverless — Vercel, Node, etc.\n');
|
|
87
139
|
let adapterRaw = '';
|
|
88
|
-
while (!['1', '2'].includes(adapterRaw)) {
|
|
89
|
-
adapterRaw = (await ask(rl, 'Adapter [1/2]: ')).trim();
|
|
90
|
-
if (!['1', '2'].includes(adapterRaw))
|
|
91
|
-
console.log(' Please enter 1 or
|
|
140
|
+
while (!['1', '2', '3'].includes(adapterRaw)) {
|
|
141
|
+
adapterRaw = (await ask(rl, 'Adapter [1/2/3]: ')).trim();
|
|
142
|
+
if (!['1', '2', '3'].includes(adapterRaw))
|
|
143
|
+
console.log(' Please enter 1, 2, or 3.');
|
|
92
144
|
}
|
|
93
|
-
const
|
|
145
|
+
const adapter = adapterRaw === '1' ? 'ssg' : adapterRaw === '2' ? 'cloudflare' : 'serverless';
|
|
94
146
|
// ── Collect files ───────────────────────────────────────────────────────
|
|
95
147
|
const sharedFiles = collectFiles(path.join(TEMPLATE_DIR, 'shared'));
|
|
96
148
|
const fullFiles = mode === 'full' ? collectFiles(path.join(TEMPLATE_DIR, 'full')) : [];
|
|
@@ -100,6 +152,16 @@ export async function main() {
|
|
|
100
152
|
];
|
|
101
153
|
const layoutTsPath = path.join(PROJECT_ROOT, 'src/routes/+layout.ts');
|
|
102
154
|
const layoutTsContent = 'export const prerender = true;\n';
|
|
155
|
+
const wranglerTomlPath = path.join(PROJECT_ROOT, 'wrangler.toml');
|
|
156
|
+
const appDtsPath = path.join(PROJECT_ROOT, 'src/app.d.ts');
|
|
157
|
+
const svelteConfigPath = path.join(PROJECT_ROOT, 'svelte.config.js');
|
|
158
|
+
const ghaWorkflowPath = path.join(PROJECT_ROOT, '.github', 'workflows', 'deploy.yml');
|
|
159
|
+
// ── GitHub Actions prompt (Cloudflare only, before conflict detection) ──
|
|
160
|
+
let generateGha = false;
|
|
161
|
+
if (adapter === 'cloudflare') {
|
|
162
|
+
const ans = (await ask(rl, '\nGenerate GitHub Actions deploy workflow? [y/N]: ')).toLowerCase();
|
|
163
|
+
generateGha = ans === 'y';
|
|
164
|
+
}
|
|
103
165
|
// ── Conflict detection ──────────────────────────────────────────────────
|
|
104
166
|
const conflicts = [];
|
|
105
167
|
for (const [, rel] of allFiles) {
|
|
@@ -107,8 +169,21 @@ export async function main() {
|
|
|
107
169
|
if (fs.existsSync(dest))
|
|
108
170
|
conflicts.push(path.relative(PROJECT_ROOT, dest));
|
|
109
171
|
}
|
|
110
|
-
if (
|
|
111
|
-
|
|
172
|
+
if (adapter === 'ssg') {
|
|
173
|
+
if (fs.existsSync(layoutTsPath))
|
|
174
|
+
conflicts.push(path.relative(PROJECT_ROOT, layoutTsPath));
|
|
175
|
+
if (fs.existsSync(svelteConfigPath))
|
|
176
|
+
conflicts.push('svelte.config.js');
|
|
177
|
+
}
|
|
178
|
+
if (adapter === 'cloudflare') {
|
|
179
|
+
if (fs.existsSync(wranglerTomlPath))
|
|
180
|
+
conflicts.push('wrangler.toml');
|
|
181
|
+
if (fs.existsSync(appDtsPath))
|
|
182
|
+
conflicts.push('src/app.d.ts');
|
|
183
|
+
if (fs.existsSync(svelteConfigPath))
|
|
184
|
+
conflicts.push('svelte.config.js');
|
|
185
|
+
if (generateGha && fs.existsSync(ghaWorkflowPath))
|
|
186
|
+
conflicts.push('.github/workflows/deploy.yml');
|
|
112
187
|
}
|
|
113
188
|
if (conflicts.length > 0) {
|
|
114
189
|
console.log('\nThe following files already exist:\n');
|
|
@@ -133,27 +208,104 @@ export async function main() {
|
|
|
133
208
|
copyFile(src, dest);
|
|
134
209
|
console.log(` created ${path.relative(PROJECT_ROOT, dest)}`);
|
|
135
210
|
}
|
|
136
|
-
if (
|
|
211
|
+
if (adapter === 'ssg') {
|
|
137
212
|
writeFile(layoutTsPath, layoutTsContent);
|
|
138
213
|
console.log(` created src/routes/+layout.ts`);
|
|
214
|
+
writeFile(svelteConfigPath, svelteConfigContent('ssg'));
|
|
215
|
+
console.log(` created svelte.config.js`);
|
|
139
216
|
}
|
|
140
|
-
|
|
217
|
+
if (adapter === 'cloudflare') {
|
|
218
|
+
writeFile(svelteConfigPath, svelteConfigContent('cloudflare'));
|
|
219
|
+
console.log(` created svelte.config.js`);
|
|
220
|
+
const projectName = readProjectName(PROJECT_ROOT);
|
|
221
|
+
const wranglerToml = [
|
|
222
|
+
`name = "${projectName}"`,
|
|
223
|
+
`compatibility_date = "${new Date().toISOString().slice(0, 10)}"`,
|
|
224
|
+
`compatibility_flags = ["nodejs_compat"]`,
|
|
225
|
+
``,
|
|
226
|
+
`# Uncomment to add Cloudflare D1 (run: bunx cosmolo migrate:db)`,
|
|
227
|
+
`# [[d1_databases]]`,
|
|
228
|
+
`# binding = "DB"`,
|
|
229
|
+
`# database_name = "${projectName}-db"`,
|
|
230
|
+
`# database_id = "" # fill in after: bunx wrangler d1 create ${projectName}-db`,
|
|
231
|
+
].join('\n') + '\n';
|
|
232
|
+
writeFile(wranglerTomlPath, wranglerToml);
|
|
233
|
+
console.log(` created wrangler.toml`);
|
|
234
|
+
const appDts = [
|
|
235
|
+
`// See https://svelte.dev/docs/kit/types#app.d.ts`,
|
|
236
|
+
`// Install @cloudflare/workers-types for full type support:`,
|
|
237
|
+
`// bun add -D @cloudflare/workers-types`,
|
|
238
|
+
`declare global {`,
|
|
239
|
+
`\tnamespace App {`,
|
|
240
|
+
`\t\tinterface Platform {`,
|
|
241
|
+
`\t\t\tenv: Env;`,
|
|
242
|
+
`\t\t\tcf: CfProperties;`,
|
|
243
|
+
`\t\t\tctx: ExecutionContext;`,
|
|
244
|
+
`\t\t}`,
|
|
245
|
+
`\t}`,
|
|
246
|
+
`}`,
|
|
247
|
+
``,
|
|
248
|
+
`export {};`,
|
|
249
|
+
].join('\n') + '\n';
|
|
250
|
+
writeFile(appDtsPath, appDts);
|
|
251
|
+
console.log(` created src/app.d.ts`);
|
|
252
|
+
if (generateGha) {
|
|
253
|
+
writeFile(ghaWorkflowPath, githubActionsContent(projectName));
|
|
254
|
+
console.log(` created .github/workflows/deploy.yml`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
injectPackageScripts(PROJECT_ROOT, adapter);
|
|
141
258
|
// ── Next steps ──────────────────────────────────────────────────────────
|
|
142
259
|
console.log('\nDone! Next steps:\n');
|
|
143
260
|
console.log(' 1. Run: bun install');
|
|
144
|
-
if (
|
|
261
|
+
if (adapter === 'ssg') {
|
|
145
262
|
console.log(' 2. Install adapter: bun add -D @sveltejs/adapter-static');
|
|
263
|
+
if (mode === 'full') {
|
|
264
|
+
console.log(' 3. Install sass: bun add -D sass (SCSS used in Svelte templates)');
|
|
265
|
+
console.log(' 4. Run: bun dev');
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
console.log(' 3. Add your own +page.svelte files for each route.');
|
|
269
|
+
console.log(' 4. Run: bun dev');
|
|
270
|
+
}
|
|
146
271
|
}
|
|
147
|
-
else {
|
|
148
|
-
console.log(' 2. Install adapter: bun add -D @sveltejs/adapter-cloudflare
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
272
|
+
else if (adapter === 'cloudflare') {
|
|
273
|
+
console.log(' 2. Install adapter: bun add -D @sveltejs/adapter-cloudflare');
|
|
274
|
+
console.log(' 3. Install types: bun add -D @cloudflare/workers-types');
|
|
275
|
+
if (generateGha) {
|
|
276
|
+
console.log(' 4. Add secret to GitHub repo: CF_API_TOKEN (Cloudflare API token)');
|
|
277
|
+
if (mode === 'full') {
|
|
278
|
+
console.log(' 5. Install sass: bun add -D sass (SCSS used in Svelte templates)');
|
|
279
|
+
console.log(' 6. Push to main — GitHub Actions will build and deploy automatically.');
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
console.log(' 5. Add your own +page.svelte files for each route.');
|
|
283
|
+
console.log(' 6. Push to main — GitHub Actions will build and deploy automatically.');
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
if (mode === 'full') {
|
|
288
|
+
console.log(' 4. Install sass: bun add -D sass (SCSS used in Svelte templates)');
|
|
289
|
+
console.log(' 5. Run: bunx wrangler dev (or bun dev for local Vite)');
|
|
290
|
+
console.log(' 6. Deploy: bun run deploy');
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
console.log(' 4. Add your own +page.svelte files for each route.');
|
|
294
|
+
console.log(' 5. Run: bunx wrangler dev (or bun dev for local Vite)');
|
|
295
|
+
console.log(' 6. Deploy: bun run deploy');
|
|
296
|
+
}
|
|
297
|
+
}
|
|
153
298
|
}
|
|
154
299
|
else {
|
|
155
|
-
console.log('
|
|
156
|
-
|
|
300
|
+
console.log(' 2. Install adapter: bun add -D @sveltejs/adapter-vercel (or your adapter)');
|
|
301
|
+
if (mode === 'full') {
|
|
302
|
+
console.log(' 3. Install sass: bun add -D sass (SCSS used in Svelte templates)');
|
|
303
|
+
console.log(' 4. Run: bun dev');
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
console.log(' 3. Add your own +page.svelte files for each route.');
|
|
307
|
+
console.log(' 4. Run: bun dev');
|
|
308
|
+
}
|
|
157
309
|
}
|
|
158
310
|
console.log('\n See https://github.com/alcogy/cosmolo for full documentation.\n');
|
|
159
311
|
}
|