bunki 0.7.0 → 0.7.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/dist/cli.js +54 -53
- package/dist/index.js +53 -52
- package/dist/utils/s3-uploader.d.ts +6 -0
- package/package.json +7 -7
package/dist/cli.js
CHANGED
|
@@ -1596,7 +1596,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1596
1596
|
return arg.length > 1 && arg[0] === "-";
|
|
1597
1597
|
}
|
|
1598
1598
|
const negativeNumberArg = (arg) => {
|
|
1599
|
-
if (
|
|
1599
|
+
if (!/^-(\d+|\d*\.\d+)(e[+-]?\d+)?$/.test(arg))
|
|
1600
1600
|
return false;
|
|
1601
1601
|
return !this._getCommandAndAncestors().some((cmd) => cmd.options.map((opt) => opt.short).some((short) => /^-\d$/.test(short)));
|
|
1602
1602
|
};
|
|
@@ -33602,6 +33602,28 @@ class S3Uploader {
|
|
|
33602
33602
|
}
|
|
33603
33603
|
}
|
|
33604
33604
|
}
|
|
33605
|
+
async executeWithConcurrency(tasks, concurrency) {
|
|
33606
|
+
const results = [];
|
|
33607
|
+
const executing = [];
|
|
33608
|
+
for (const task of tasks) {
|
|
33609
|
+
const promise = task().then((result) => {
|
|
33610
|
+
results.push(result);
|
|
33611
|
+
const index = executing.indexOf(promise);
|
|
33612
|
+
if (index > -1)
|
|
33613
|
+
executing.splice(index, 1);
|
|
33614
|
+
}).catch((error) => {
|
|
33615
|
+
const index = executing.indexOf(promise);
|
|
33616
|
+
if (index > -1)
|
|
33617
|
+
executing.splice(index, 1);
|
|
33618
|
+
});
|
|
33619
|
+
executing.push(promise);
|
|
33620
|
+
if (executing.length >= concurrency) {
|
|
33621
|
+
await Promise.race(executing);
|
|
33622
|
+
}
|
|
33623
|
+
}
|
|
33624
|
+
await Promise.all(executing);
|
|
33625
|
+
return results;
|
|
33626
|
+
}
|
|
33605
33627
|
async uploadImages(imagesDir, minYear) {
|
|
33606
33628
|
console.log(`[S3] Uploading all images from ${imagesDir} to bucket ${this.s3Config.bucket}...`);
|
|
33607
33629
|
if (minYear) {
|
|
@@ -33609,59 +33631,30 @@ class S3Uploader {
|
|
|
33609
33631
|
}
|
|
33610
33632
|
const imageUrls = {};
|
|
33611
33633
|
try {
|
|
33612
|
-
console.log(`[S3] Checking if directory exists: ${imagesDir}`);
|
|
33613
|
-
try {
|
|
33614
|
-
const glob2 = new Bun.Glob("**/*");
|
|
33615
|
-
let hasContent = false;
|
|
33616
|
-
for await (const file of glob2.scan({
|
|
33617
|
-
cwd: imagesDir,
|
|
33618
|
-
absolute: false
|
|
33619
|
-
})) {
|
|
33620
|
-
hasContent = true;
|
|
33621
|
-
break;
|
|
33622
|
-
}
|
|
33623
|
-
if (!hasContent) {
|
|
33624
|
-
console.warn(`Directory exists but is empty: ${imagesDir}`);
|
|
33625
|
-
}
|
|
33626
|
-
console.log(`[S3] Directory exists and is accessible`);
|
|
33627
|
-
} catch (err) {
|
|
33628
|
-
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
33629
|
-
console.warn(`No images directory found at ${imagesDir}, skipping image upload. Error: ${errorMessage}`);
|
|
33630
|
-
return imageUrls;
|
|
33631
|
-
}
|
|
33632
33634
|
const glob = new Bun.Glob("**/*.{jpg,jpeg,png,gif,webp,svg}");
|
|
33633
33635
|
const files = [];
|
|
33634
33636
|
console.log(`[S3] Scanning directory ${imagesDir} for image files...`);
|
|
33635
33637
|
try {
|
|
33636
|
-
const
|
|
33637
|
-
const allFiles = [];
|
|
33638
|
-
for await (const file of dirGlob.scan({
|
|
33638
|
+
for await (const file of glob.scan({
|
|
33639
33639
|
cwd: imagesDir,
|
|
33640
33640
|
absolute: false
|
|
33641
33641
|
})) {
|
|
33642
|
-
|
|
33643
|
-
|
|
33644
|
-
|
|
33645
|
-
|
|
33646
|
-
|
|
33647
|
-
|
|
33648
|
-
|
|
33649
|
-
cwd: imagesDir,
|
|
33650
|
-
absolute: false
|
|
33651
|
-
})) {
|
|
33652
|
-
if (minYear) {
|
|
33653
|
-
const yearMatch = file.match(/^(\d{4})\//);
|
|
33654
|
-
if (yearMatch) {
|
|
33655
|
-
const fileYear = parseInt(yearMatch[1], 10);
|
|
33656
|
-
if (fileYear >= minYear) {
|
|
33657
|
-
console.log(`[S3] Found image file: ${file}`);
|
|
33658
|
-
files.push(file);
|
|
33642
|
+
if (minYear) {
|
|
33643
|
+
const yearMatch = file.match(/^(\d{4})\//);
|
|
33644
|
+
if (yearMatch) {
|
|
33645
|
+
const fileYear = parseInt(yearMatch[1], 10);
|
|
33646
|
+
if (fileYear >= minYear) {
|
|
33647
|
+
files.push(file);
|
|
33648
|
+
}
|
|
33659
33649
|
}
|
|
33650
|
+
} else {
|
|
33651
|
+
files.push(file);
|
|
33660
33652
|
}
|
|
33661
|
-
} else {
|
|
33662
|
-
console.log(`[S3] Found image file: ${file}`);
|
|
33663
|
-
files.push(file);
|
|
33664
33653
|
}
|
|
33654
|
+
} catch (err) {
|
|
33655
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
33656
|
+
console.warn(`Error scanning images directory: ${errorMessage}`);
|
|
33657
|
+
return imageUrls;
|
|
33665
33658
|
}
|
|
33666
33659
|
const imageFiles = files;
|
|
33667
33660
|
if (imageFiles.length === 0) {
|
|
@@ -33669,27 +33662,35 @@ class S3Uploader {
|
|
|
33669
33662
|
return imageUrls;
|
|
33670
33663
|
}
|
|
33671
33664
|
console.log(`Found ${imageFiles.length} images to upload`);
|
|
33672
|
-
|
|
33665
|
+
console.log(`[S3] Processing with 10 concurrent uploads...`);
|
|
33666
|
+
const concurrencyLimit = 10;
|
|
33667
|
+
let uploadedCount = 0;
|
|
33668
|
+
let failedCount = 0;
|
|
33669
|
+
const uploadTasks = imageFiles.map((imageFile) => async () => {
|
|
33673
33670
|
try {
|
|
33674
33671
|
const imagePath = path7.join(imagesDir, imageFile);
|
|
33675
33672
|
const filename = path7.basename(imagePath);
|
|
33676
|
-
console.log(`[S3] Uploading image ${imagePath} to S3 bucket ${this.s3Config.bucket}/${imageFile}...`);
|
|
33677
33673
|
const file = Bun.file(imagePath);
|
|
33678
33674
|
const contentType = file.type;
|
|
33679
|
-
if (process.env.BUNKI_DRY_RUN === "true") {
|
|
33680
|
-
console.log(`[S3] Dry run: would upload ${imageFile} with content type ${contentType}`);
|
|
33681
|
-
} else {
|
|
33675
|
+
if (process.env.BUNKI_DRY_RUN === "true") {} else {
|
|
33682
33676
|
const s3File = this.client.file(imageFile);
|
|
33683
33677
|
await s3File.write(file);
|
|
33684
33678
|
}
|
|
33685
33679
|
const imageUrl = this.getPublicUrl(imageFile);
|
|
33686
|
-
console.log(`[S3] Image uploaded to ${imageUrl}`);
|
|
33687
33680
|
imageUrls[imageFile] = imageUrl;
|
|
33681
|
+
uploadedCount++;
|
|
33682
|
+
if (uploadedCount % 10 === 0) {
|
|
33683
|
+
console.log(`[S3] Progress: ${uploadedCount}/${imageFiles.length} images uploaded`);
|
|
33684
|
+
}
|
|
33685
|
+
return { success: true, file: imageFile };
|
|
33688
33686
|
} catch (error) {
|
|
33689
|
-
|
|
33687
|
+
failedCount++;
|
|
33688
|
+
console.error(`[S3] Error uploading ${imageFile}:`, error);
|
|
33689
|
+
return { success: false, file: imageFile };
|
|
33690
33690
|
}
|
|
33691
|
-
}
|
|
33692
|
-
|
|
33691
|
+
});
|
|
33692
|
+
await this.executeWithConcurrency(uploadTasks, concurrencyLimit);
|
|
33693
|
+
console.log(`[S3] Upload complete: ${uploadedCount} succeeded, ${failedCount} failed out of ${imageFiles.length} images`);
|
|
33693
33694
|
return imageUrls;
|
|
33694
33695
|
} catch (error) {
|
|
33695
33696
|
console.error(`Error uploading images:`, error);
|
package/dist/index.js
CHANGED
|
@@ -31509,6 +31509,28 @@ class S3Uploader {
|
|
|
31509
31509
|
}
|
|
31510
31510
|
}
|
|
31511
31511
|
}
|
|
31512
|
+
async executeWithConcurrency(tasks, concurrency) {
|
|
31513
|
+
const results = [];
|
|
31514
|
+
const executing = [];
|
|
31515
|
+
for (const task of tasks) {
|
|
31516
|
+
const promise = task().then((result) => {
|
|
31517
|
+
results.push(result);
|
|
31518
|
+
const index = executing.indexOf(promise);
|
|
31519
|
+
if (index > -1)
|
|
31520
|
+
executing.splice(index, 1);
|
|
31521
|
+
}).catch((error) => {
|
|
31522
|
+
const index = executing.indexOf(promise);
|
|
31523
|
+
if (index > -1)
|
|
31524
|
+
executing.splice(index, 1);
|
|
31525
|
+
});
|
|
31526
|
+
executing.push(promise);
|
|
31527
|
+
if (executing.length >= concurrency) {
|
|
31528
|
+
await Promise.race(executing);
|
|
31529
|
+
}
|
|
31530
|
+
}
|
|
31531
|
+
await Promise.all(executing);
|
|
31532
|
+
return results;
|
|
31533
|
+
}
|
|
31512
31534
|
async uploadImages(imagesDir, minYear) {
|
|
31513
31535
|
console.log(`[S3] Uploading all images from ${imagesDir} to bucket ${this.s3Config.bucket}...`);
|
|
31514
31536
|
if (minYear) {
|
|
@@ -31516,59 +31538,30 @@ class S3Uploader {
|
|
|
31516
31538
|
}
|
|
31517
31539
|
const imageUrls = {};
|
|
31518
31540
|
try {
|
|
31519
|
-
console.log(`[S3] Checking if directory exists: ${imagesDir}`);
|
|
31520
|
-
try {
|
|
31521
|
-
const glob2 = new Bun.Glob("**/*");
|
|
31522
|
-
let hasContent = false;
|
|
31523
|
-
for await (const file of glob2.scan({
|
|
31524
|
-
cwd: imagesDir,
|
|
31525
|
-
absolute: false
|
|
31526
|
-
})) {
|
|
31527
|
-
hasContent = true;
|
|
31528
|
-
break;
|
|
31529
|
-
}
|
|
31530
|
-
if (!hasContent) {
|
|
31531
|
-
console.warn(`Directory exists but is empty: ${imagesDir}`);
|
|
31532
|
-
}
|
|
31533
|
-
console.log(`[S3] Directory exists and is accessible`);
|
|
31534
|
-
} catch (err) {
|
|
31535
|
-
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
31536
|
-
console.warn(`No images directory found at ${imagesDir}, skipping image upload. Error: ${errorMessage}`);
|
|
31537
|
-
return imageUrls;
|
|
31538
|
-
}
|
|
31539
31541
|
const glob = new Bun.Glob("**/*.{jpg,jpeg,png,gif,webp,svg}");
|
|
31540
31542
|
const files = [];
|
|
31541
31543
|
console.log(`[S3] Scanning directory ${imagesDir} for image files...`);
|
|
31542
31544
|
try {
|
|
31543
|
-
const
|
|
31544
|
-
const allFiles = [];
|
|
31545
|
-
for await (const file of dirGlob.scan({
|
|
31545
|
+
for await (const file of glob.scan({
|
|
31546
31546
|
cwd: imagesDir,
|
|
31547
31547
|
absolute: false
|
|
31548
31548
|
})) {
|
|
31549
|
-
|
|
31550
|
-
|
|
31551
|
-
|
|
31552
|
-
|
|
31553
|
-
|
|
31554
|
-
|
|
31555
|
-
|
|
31556
|
-
cwd: imagesDir,
|
|
31557
|
-
absolute: false
|
|
31558
|
-
})) {
|
|
31559
|
-
if (minYear) {
|
|
31560
|
-
const yearMatch = file.match(/^(\d{4})\//);
|
|
31561
|
-
if (yearMatch) {
|
|
31562
|
-
const fileYear = parseInt(yearMatch[1], 10);
|
|
31563
|
-
if (fileYear >= minYear) {
|
|
31564
|
-
console.log(`[S3] Found image file: ${file}`);
|
|
31565
|
-
files.push(file);
|
|
31549
|
+
if (minYear) {
|
|
31550
|
+
const yearMatch = file.match(/^(\d{4})\//);
|
|
31551
|
+
if (yearMatch) {
|
|
31552
|
+
const fileYear = parseInt(yearMatch[1], 10);
|
|
31553
|
+
if (fileYear >= minYear) {
|
|
31554
|
+
files.push(file);
|
|
31555
|
+
}
|
|
31566
31556
|
}
|
|
31557
|
+
} else {
|
|
31558
|
+
files.push(file);
|
|
31567
31559
|
}
|
|
31568
|
-
} else {
|
|
31569
|
-
console.log(`[S3] Found image file: ${file}`);
|
|
31570
|
-
files.push(file);
|
|
31571
31560
|
}
|
|
31561
|
+
} catch (err) {
|
|
31562
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
31563
|
+
console.warn(`Error scanning images directory: ${errorMessage}`);
|
|
31564
|
+
return imageUrls;
|
|
31572
31565
|
}
|
|
31573
31566
|
const imageFiles = files;
|
|
31574
31567
|
if (imageFiles.length === 0) {
|
|
@@ -31576,27 +31569,35 @@ class S3Uploader {
|
|
|
31576
31569
|
return imageUrls;
|
|
31577
31570
|
}
|
|
31578
31571
|
console.log(`Found ${imageFiles.length} images to upload`);
|
|
31579
|
-
|
|
31572
|
+
console.log(`[S3] Processing with 10 concurrent uploads...`);
|
|
31573
|
+
const concurrencyLimit = 10;
|
|
31574
|
+
let uploadedCount = 0;
|
|
31575
|
+
let failedCount = 0;
|
|
31576
|
+
const uploadTasks = imageFiles.map((imageFile) => async () => {
|
|
31580
31577
|
try {
|
|
31581
31578
|
const imagePath = path6.join(imagesDir, imageFile);
|
|
31582
31579
|
const filename = path6.basename(imagePath);
|
|
31583
|
-
console.log(`[S3] Uploading image ${imagePath} to S3 bucket ${this.s3Config.bucket}/${imageFile}...`);
|
|
31584
31580
|
const file = Bun.file(imagePath);
|
|
31585
31581
|
const contentType = file.type;
|
|
31586
|
-
if (process.env.BUNKI_DRY_RUN === "true") {
|
|
31587
|
-
console.log(`[S3] Dry run: would upload ${imageFile} with content type ${contentType}`);
|
|
31588
|
-
} else {
|
|
31582
|
+
if (process.env.BUNKI_DRY_RUN === "true") {} else {
|
|
31589
31583
|
const s3File = this.client.file(imageFile);
|
|
31590
31584
|
await s3File.write(file);
|
|
31591
31585
|
}
|
|
31592
31586
|
const imageUrl = this.getPublicUrl(imageFile);
|
|
31593
|
-
console.log(`[S3] Image uploaded to ${imageUrl}`);
|
|
31594
31587
|
imageUrls[imageFile] = imageUrl;
|
|
31588
|
+
uploadedCount++;
|
|
31589
|
+
if (uploadedCount % 10 === 0) {
|
|
31590
|
+
console.log(`[S3] Progress: ${uploadedCount}/${imageFiles.length} images uploaded`);
|
|
31591
|
+
}
|
|
31592
|
+
return { success: true, file: imageFile };
|
|
31595
31593
|
} catch (error) {
|
|
31596
|
-
|
|
31594
|
+
failedCount++;
|
|
31595
|
+
console.error(`[S3] Error uploading ${imageFile}:`, error);
|
|
31596
|
+
return { success: false, file: imageFile };
|
|
31597
31597
|
}
|
|
31598
|
-
}
|
|
31599
|
-
|
|
31598
|
+
});
|
|
31599
|
+
await this.executeWithConcurrency(uploadTasks, concurrencyLimit);
|
|
31600
|
+
console.log(`[S3] Upload complete: ${uploadedCount} succeeded, ${failedCount} failed out of ${imageFiles.length} images`);
|
|
31600
31601
|
return imageUrls;
|
|
31601
31602
|
} catch (error) {
|
|
31602
31603
|
console.error(`Error uploading images:`, error);
|
|
@@ -13,6 +13,12 @@ export declare class S3Uploader implements Uploader, ImageUploader {
|
|
|
13
13
|
* @returns The public URL for the file
|
|
14
14
|
*/
|
|
15
15
|
private getPublicUrl;
|
|
16
|
+
/**
|
|
17
|
+
* Execute async tasks with concurrency limit
|
|
18
|
+
* @param tasks Array of task functions that return promises
|
|
19
|
+
* @param concurrency Maximum number of concurrent tasks
|
|
20
|
+
*/
|
|
21
|
+
private executeWithConcurrency;
|
|
16
22
|
uploadImages(imagesDir: string, minYear?: number): Promise<Record<string, string>>;
|
|
17
23
|
}
|
|
18
24
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bunki",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "An opinionated static site generator built with Bun featuring PostCSS integration and modern web development workflows",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
},
|
|
48
48
|
"homepage": "https://github.com/kahwee/bunki#readme",
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"commander": "^14.0.
|
|
50
|
+
"commander": "^14.0.2",
|
|
51
51
|
"gray-matter": "^4.0.3",
|
|
52
52
|
"highlight.js": "^11.11.1",
|
|
53
53
|
"marked": "^16.4.1",
|
|
@@ -59,15 +59,15 @@
|
|
|
59
59
|
"slugify": "^1.6.6"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@tailwindcss/postcss": "^4.1.
|
|
62
|
+
"@tailwindcss/postcss": "^4.1.16",
|
|
63
63
|
"@types/nunjucks": "^3.2.6",
|
|
64
64
|
"@types/sanitize-html": "^2.16.0",
|
|
65
|
-
"autoprefixer": "^10.4.
|
|
66
|
-
"bun-types": "^1.3.
|
|
65
|
+
"autoprefixer": "^10.4.21",
|
|
66
|
+
"bun-types": "^1.3.1",
|
|
67
67
|
"husky": "^9.1.7",
|
|
68
|
-
"lint-staged": "^16.2.
|
|
68
|
+
"lint-staged": "^16.2.6",
|
|
69
69
|
"prettier": "^3.6.2",
|
|
70
|
-
"tailwindcss": "^4.1.
|
|
70
|
+
"tailwindcss": "^4.1.16",
|
|
71
71
|
"typescript": "^5.9.3"
|
|
72
72
|
},
|
|
73
73
|
"peerDependencies": {
|