bunki 0.19.6 → 0.21.1

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 CHANGED
@@ -8,19 +8,24 @@ Fast static site generator for blogs and documentation built with Bun. Supports
8
8
 
9
9
  ## Install
10
10
 
11
- Requires **Bun v1.3.0+** (recommended) or Node.js v18+
11
+ Requires **Bun v1.3.14+**. Bun v1.3.14 is the latest stable Bun release currently supported by this project. Bun is the supported runtime for installing, building, testing, and running Bunki.
12
12
 
13
- ```bash
14
- # Install globally with Bun
15
- bun install -g bunki
13
+ Check your runtime before working on Bunki:
16
14
 
17
- # Or with npm
18
- npm install -g bunki
15
+ ```bash
16
+ bun --version # should report 1.3.14 or newer
17
+ ```
19
18
 
20
- # Or in your project
19
+ ```bash
20
+ # Install in your project
21
21
  bun install bunki
22
+
23
+ # Or install the CLI globally with Bun
24
+ bun install -g bunki
22
25
  ```
23
26
 
27
+ Do not use `npm`, `yarn`, or `pnpm` for Bunki workflows. The CLI, scripts, and test suite are designed for Bun.
28
+
24
29
  ## Quick Start
25
30
 
26
31
  ```bash
@@ -55,19 +60,22 @@ export default (): SiteConfig => ({
55
60
 
56
61
  // Optional: Image upload to Cloudflare R2 or S3
57
62
  s3: {
58
- accessKeyId: process.env.R2_ACCESS_KEY_ID || "",
59
- secretAccessKey: process.env.R2_SECRET_ACCESS_KEY || "",
60
- bucket: process.env.R2_BUCKET || "",
61
- endpoint: process.env.R2_ENDPOINT,
62
- region: process.env.R2_REGION || "auto",
63
- publicUrl: process.env.R2_PUBLIC_URL || "",
63
+ accessKeyId: process.env.S3_ACCESS_KEY_ID || "",
64
+ secretAccessKey: process.env.S3_SECRET_ACCESS_KEY || "",
65
+ bucket: process.env.S3_BUCKET || "",
66
+ endpoint: process.env.S3_ENDPOINT,
67
+ region: process.env.S3_REGION || "auto",
68
+ publicUrl: process.env.S3_PUBLIC_URL || "",
64
69
  },
65
70
  });
66
71
  ```
67
72
 
68
73
  ## Content & Frontmatter
69
74
 
70
- Create Markdown files in `content/YYYY/` using either pattern:
75
+ Create Markdown files anywhere under `content/` using either pattern:
76
+
77
+ - Year folders are a good fit for organizing posts and colocated assets.
78
+ - The published URL year comes from the post date in frontmatter, not the file path.
71
79
 
72
80
  **Option 1: Single file** (traditional)
73
81
 
@@ -466,19 +474,19 @@ Fragments are standard Nunjucks macro files. You can place your own in your site
466
474
 
467
475
  ### Overview
468
476
 
469
- The `images:push` command uploads local media (images and videos) to Cloudflare R2, AWS S3, or any S3-compatible storage provider. Media files are organized by year in the `images/` directory and uploaded with their full directory structure preserved.
477
+ The `images:push` command uploads local media (images, SVG, and videos) to Cloudflare R2, AWS S3, or any S3-compatible storage provider. Media files are organized by year in the `assets/` directory and uploaded with their full directory structure preserved.
470
478
 
471
479
  **Supported formats:**
472
480
 
473
481
  - **Images:** JPG, JPEG, PNG, GIF, WebP, SVG
474
- - **Video:** MP4
482
+ - **Video:** MP4, WebM, MOV
475
483
 
476
484
  ### Directory Structure
477
485
 
478
486
  Organize images by year and post slug:
479
487
 
480
488
  ```
481
- images/
489
+ assets/
482
490
  ├── 2023/
483
491
  │ ├── post-slug-1/
484
492
  │ │ ├── image-1.jpg
@@ -551,7 +559,7 @@ bunki images:push
551
559
 
552
560
  This command:
553
561
 
554
- 1. Scans the `images/` directory recursively
562
+ 1. Scans the `assets/` directory recursively by default
555
563
  2. Uploads all supported image formats
556
564
  3. Preserves the directory structure (year/slug/filename)
557
565
  4. Generates public URLs for each image
@@ -560,7 +568,7 @@ This command:
560
568
 
561
569
  #### `--images <dir>`
562
570
 
563
- Specify a custom images directory (default: `./images`)
571
+ Specify a custom images directory (default: `./assets`)
564
572
 
565
573
  ```bash
566
574
  bunki images:push --images ./assets/images
@@ -612,6 +620,15 @@ This is useful for:
612
620
  - Testing uploads for specific years
613
621
  - Managing large image collections across multiple uploads
614
622
 
623
+ #### `--max-year <year>`
624
+
625
+ Upload only images up to and including the specified year
626
+
627
+ ```bash
628
+ # Upload only 2023 and older images
629
+ bunki images:push --max-year 2023
630
+ ```
631
+
615
632
  #### `--content-assets`
616
633
 
617
634
  Upload images that are co-located with markdown files instead of the top-level `assets/` directory.
@@ -775,7 +792,7 @@ Check out the making of the vlog:
775
792
  **Video Upload Example:**
776
793
 
777
794
  ```bash
778
- # Upload all images and videos (including MP4 files)
795
+ # Upload all images and videos (including MP4, WebM, and MOV files)
779
796
  bunki images:push
780
797
 
781
798
  # Upload only 2024 videos and images
@@ -847,9 +864,9 @@ Ensure all required environment variables are set. Check `bunki.config.ts` and y
847
864
 
848
865
  #### "No image files found"
849
866
 
850
- - Verify images exist in `images/` directory
851
- - Check that files have supported extensions (.jpg, .png, .gif, .webp, .svg)
852
- - Ensure the directory structure is correct (e.g., `images/2024/post-slug/image.jpg`)
867
+ - Verify images exist in `assets/` directory
868
+ - Check that files have supported extensions (.jpg, .jpeg, .png, .gif, .webp)
869
+ - Ensure the directory structure is correct (e.g., `assets/2024/post-slug/image.jpg`)
853
870
 
854
871
  #### "Unauthorized" or "Access Denied"
855
872
 
@@ -966,7 +983,7 @@ export S3_PUBLIC_URL="https://img.example.com"
966
983
  4. **Use modern formats** (WebP) for better compression:
967
984
  - JPG/PNG for screenshots
968
985
  - WebP for photos
969
- - SVG for icons/graphics
986
+ - SVG for icons/graphics in site assets
970
987
 
971
988
  ## Incremental Builds
972
989
 
@@ -1084,7 +1101,7 @@ Version 2.0.0 cache structure:
1084
1101
 
1085
1102
  ### Future Optimizations
1086
1103
 
1087
- Current implementation (v0.18.0) optimizes parsing and CSS processing. Future versions may add:
1104
+ Current implementation (v0.21.0) optimizes parsing and CSS processing. Future versions may add:
1088
1105
 
1089
1106
  - Selective page regeneration (only rebuild changed posts)
1090
1107
  - Incremental sitemap/RSS updates
@@ -1093,14 +1110,17 @@ Current implementation (v0.18.0) optimizes parsing and CSS processing. Future ve
1093
1110
  ## CLI Commands
1094
1111
 
1095
1112
  ```bash
1096
- bunki init [--config FILE] # Initialize new site
1097
- bunki new <TITLE> [--tags TAG1,TAG2] # Create new post
1098
- bunki generate [--config FILE] # Build static site (full)
1099
- bunki generate --incremental # Build with caching (3x faster)
1100
- bunki validate [--config FILE] # Validate frontmatter
1101
- bunki serve [--port 3000] # Start dev server
1102
- bunki css [--watch] # Process CSS
1103
- bunki images:push [--domain DOMAIN] # Upload images to cloud
1113
+ bunki init [--config FILE] # Initialize new site
1114
+ bunki new <TITLE> [--tags TAG1,TAG2] # Create new post
1115
+ bunki generate [--config FILE] [--content DIR] [--output DIR] [--templates DIR]
1116
+ bunki generate --incremental # Enable incremental builds
1117
+ bunki validate [--config FILE] [--dir DIR] # Validate markdown files for parsing errors
1118
+ bunki validate:media [--content-dir DIR] # Validate media files
1119
+ bunki serve [--output DIR] [--port 3000] # Start dev server
1120
+ bunki css [--config FILE] [--output DIR] [--watch] # Process CSS
1121
+ bunki images:push [--domain DOMAIN] [--images DIR] [--output-json FILE]
1122
+ [--min-year YEAR] [--max-year YEAR] [--content-assets] [--content-assets-dir DIR]
1123
+ # Upload media to S3-compatible storage
1104
1124
  ```
1105
1125
 
1106
1126
  ## Output Structure
@@ -1202,7 +1222,7 @@ site-generator.ts (orchestrator)
1202
1222
  - **JSON-LD Structured Data**: Automatic Schema.org markup (BlogPosting, WebSite, Organization, BreadcrumbList)
1203
1223
  - **Pagination**: Configurable posts per page with reusable pagination utilities
1204
1224
  - **Archives**: Year-based and tag-based organization
1205
- - **Modular Architecture**: Single responsibility modules with comprehensive test coverage (424 tests)
1225
+ - **Modular Architecture**: Single responsibility modules with comprehensive test coverage
1206
1226
 
1207
1227
  ## Development
1208
1228
 
@@ -1215,9 +1235,21 @@ bun run build # Build distribution
1215
1235
  bun test # Run test suite
1216
1236
  bun test:coverage # Test coverage report
1217
1237
  bun run typecheck # TypeScript validation
1218
- bun run format # Prettier formatting
1238
+ bun run format # Biome formatting
1219
1239
  ```
1220
1240
 
1241
+ ## Continuous Integration
1242
+
1243
+ GitHub Actions runs the same Bun-first workflow used locally:
1244
+
1245
+ - **CI**: typecheck, Biome linting, coverage tests, build, and an example site generation smoke test.
1246
+ - **Compatibility Tests**: verifies the minimum supported Bun version (`1.3.14`) and the latest Bun release.
1247
+ - **Coverage**: generates LCOV coverage and uploads it to Coveralls.
1248
+ - **PR Coverage Comment**: posts LCOV coverage feedback on pull requests.
1249
+ - **Publish to npm**: runs tests and builds first, then publishes on version tags, `[publish]` commits, or manual dispatch with `force-publish`.
1250
+
1251
+ Shared workflow setup lives in `.github/actions/setup-bun/action.yml`, which installs Bun, restores the Bun package cache, and runs `bun install --frozen-lockfile`.
1252
+
1221
1253
  ## Project Structure
1222
1254
 
1223
1255
  ```
@@ -1247,7 +1279,7 @@ bunki/
1247
1279
  │ ├── json-ld.ts # JSON-LD schema generation
1248
1280
  │ ├── image-uploader.ts # Image upload logic
1249
1281
  │ └── s3-uploader.ts # S3/R2 client
1250
- ├── test/ # Test suite (424 tests, mirrors src/)
1282
+ ├── test/ # Test suite (mirrors src/)
1251
1283
  │ ├── utils/
1252
1284
  │ │ ├── markdown/ # Modular tests (NEW)
1253
1285
  │ │ │ ├── constants.test.ts (25 tests)
@@ -1,4 +1,4 @@
1
- import { Command } from "commander";
1
+ import type { Command } from "commander";
2
2
  import { loadConfig } from "../../config";
3
3
  import { getDefaultCSSConfig, processCSS, watchCSS } from "../../utils/css-processor";
4
4
  interface CssDeps {
@@ -1,4 +1,4 @@
1
- import { Command } from "commander";
1
+ import type { Command } from "commander";
2
2
  import { loadConfig } from "../../config";
3
3
  import { SiteGenerator } from "../../site-generator";
4
4
  interface GenerateDeps {
@@ -1,4 +1,4 @@
1
- import { Command } from "commander";
1
+ import type { Command } from "commander";
2
2
  import { uploadImages } from "../../utils/image-uploader";
3
3
  interface ImagesPushDeps {
4
4
  uploadImages: typeof uploadImages;
@@ -1,4 +1,4 @@
1
- import { Command } from "commander";
1
+ import type { Command } from "commander";
2
2
  import { createDefaultConfig } from "../../config";
3
3
  import { ensureDir } from "../../utils/file-utils";
4
4
  type WriteFileFn = (filePath: string, data: string) => Promise<number>;
@@ -1,4 +1,4 @@
1
- import { Command } from "commander";
1
+ import type { Command } from "commander";
2
2
  type WriteFileFn = (filePath: string, data: string) => Promise<number>;
3
3
  interface NewDeps {
4
4
  writeFile: WriteFileFn;
@@ -1,4 +1,4 @@
1
- import { Command } from "commander";
1
+ import type { Command } from "commander";
2
2
  import { startServer } from "../../server";
3
3
  interface ServeDeps {
4
4
  startServer: typeof startServer;
@@ -1,7 +1,6 @@
1
- import { Command } from "commander";
1
+ import type { Command } from "commander";
2
2
  export declare function handleValidateMediaCommand(options: {
3
3
  contentDir?: string;
4
- fix?: boolean;
5
4
  }, deps?: {
6
5
  logger: Console;
7
6
  exit: (code: number) => never;
@@ -1,2 +1,2 @@
1
- import { Command } from "commander";
1
+ import type { Command } from "commander";
2
2
  export declare function registerValidateCommand(program: Command): void;