@leadertechie/personal-site-kit 0.1.0-alpha.17 → 0.1.0-alpha.18
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../../src/api/handlers/content.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../../src/api/handlers/content.ts"],"names":[],"mappings":"AAqBA,wBAAsB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAqElG"}
|
package/dist/api.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { W as WebsiteAPI } from "./chunks/website-api-
|
|
2
|
-
import { A, B, M, R, c, a, g, b, d, h, e, r, s, v } from "./chunks/website-api-
|
|
1
|
+
import { W as WebsiteAPI } from "./chunks/website-api-DBEh24zq.js";
|
|
2
|
+
import { A, B, M, R, c, a, g, b, d, h, e, r, s, v } from "./chunks/website-api-DBEh24zq.js";
|
|
3
3
|
const defaultAPI = new WebsiteAPI();
|
|
4
4
|
export {
|
|
5
5
|
A as AUTH_KV,
|
|
@@ -50,7 +50,7 @@ function getLoader$1(env) {
|
|
|
50
50
|
}
|
|
51
51
|
return loader$1;
|
|
52
52
|
}
|
|
53
|
-
function clearContentCache$
|
|
53
|
+
function clearContentCache$2() {
|
|
54
54
|
loader$1?.clearCache();
|
|
55
55
|
}
|
|
56
56
|
async function handleAboutMe(env) {
|
|
@@ -145,7 +145,7 @@ function getLoader(env) {
|
|
|
145
145
|
}
|
|
146
146
|
return loader;
|
|
147
147
|
}
|
|
148
|
-
function clearContentCache() {
|
|
148
|
+
function clearContentCache$1() {
|
|
149
149
|
loader?.clearCache();
|
|
150
150
|
}
|
|
151
151
|
async function handleHome(env) {
|
|
@@ -295,6 +295,128 @@ async function verifyCredentials(env, username, password) {
|
|
|
295
295
|
function getClientIP(request) {
|
|
296
296
|
return request.headers.get("CF-Connecting-IP") || request.headers.get("X-Forwarded-For")?.split(",")[0]?.trim() || "unknown";
|
|
297
297
|
}
|
|
298
|
+
const contentCache = new ContentCacheV2(
|
|
299
|
+
5 * 60 * 1e3,
|
|
300
|
+
// TTL: 5 minutes fresh
|
|
301
|
+
true,
|
|
302
|
+
// enabled
|
|
303
|
+
30 * 60 * 1e3
|
|
304
|
+
// SWR TTL: 30 minutes stale window
|
|
305
|
+
);
|
|
306
|
+
function getCachedOrFetch(key, fetchFn) {
|
|
307
|
+
const cached = contentCache.get(key);
|
|
308
|
+
if (cached) {
|
|
309
|
+
if (!cached.stale) {
|
|
310
|
+
return Promise.resolve(cached.data);
|
|
311
|
+
}
|
|
312
|
+
fetchFn().then((data) => {
|
|
313
|
+
contentCache.set(key, data);
|
|
314
|
+
contentCache.refresh(key);
|
|
315
|
+
}).catch(() => {
|
|
316
|
+
});
|
|
317
|
+
return Promise.resolve(cached.data);
|
|
318
|
+
}
|
|
319
|
+
return fetchFn().then((data) => {
|
|
320
|
+
contentCache.set(key, data);
|
|
321
|
+
return data;
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
function clearContentCache(prefix) {
|
|
325
|
+
{
|
|
326
|
+
contentCache.clear();
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
function parseFrontmatter(content) {
|
|
330
|
+
const lines = content.split("\n");
|
|
331
|
+
const metadata = {};
|
|
332
|
+
let contentStart = 0;
|
|
333
|
+
if (lines[0]?.trim() === "---") {
|
|
334
|
+
for (let i = 1; i < lines.length; i++) {
|
|
335
|
+
if (lines[i]?.trim() === "---") {
|
|
336
|
+
contentStart = i + 1;
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
339
|
+
const colonIdx = lines[i].indexOf(":");
|
|
340
|
+
if (colonIdx > 0) {
|
|
341
|
+
const key = lines[i].slice(0, colonIdx).trim();
|
|
342
|
+
let value = lines[i].slice(colonIdx + 1).trim();
|
|
343
|
+
if (value.startsWith("[") && value.endsWith("]")) {
|
|
344
|
+
value = value.slice(1, -1);
|
|
345
|
+
metadata[key] = value.split(",").map((v) => v.trim());
|
|
346
|
+
} else {
|
|
347
|
+
metadata[key] = value;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return {
|
|
353
|
+
metadata,
|
|
354
|
+
content: lines.slice(contentStart).join("\n").trim()
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
function checkContentBucket(env) {
|
|
358
|
+
if (!env?.CONTENT_BUCKET) {
|
|
359
|
+
return createErrorResponse("Content bucket not configured", 500);
|
|
360
|
+
}
|
|
361
|
+
return null;
|
|
362
|
+
}
|
|
363
|
+
async function fetchContentItem(bucket, type, slug) {
|
|
364
|
+
const mdObj = await bucket.get(`${type}/${slug}.md`);
|
|
365
|
+
const jsonObj = await bucket.get(`${type}/${slug}.json`);
|
|
366
|
+
if (!mdObj && !jsonObj) throw new Error(`${type.slice(0, -1)} not found`);
|
|
367
|
+
let metadata = {};
|
|
368
|
+
if (jsonObj) {
|
|
369
|
+
metadata = await jsonObj.json();
|
|
370
|
+
}
|
|
371
|
+
let content = "";
|
|
372
|
+
if (mdObj) {
|
|
373
|
+
const text = await mdObj.text();
|
|
374
|
+
const parsed = parseFrontmatter(text);
|
|
375
|
+
content = parsed.content;
|
|
376
|
+
metadata = { ...parsed.metadata, ...metadata };
|
|
377
|
+
}
|
|
378
|
+
return { ...metadata, slug, content };
|
|
379
|
+
}
|
|
380
|
+
async function fetchContentList(bucket, type, latest) {
|
|
381
|
+
const list = await bucket.list({ prefix: `${type}/` });
|
|
382
|
+
const items = [];
|
|
383
|
+
for (const item of list.objects) {
|
|
384
|
+
if (item.key.endsWith(".json")) {
|
|
385
|
+
const obj = await bucket.get(item.key);
|
|
386
|
+
if (obj) {
|
|
387
|
+
const metadata = await obj.json();
|
|
388
|
+
const slug = item.key.replace(`${type}/`, "").replace(".json", "");
|
|
389
|
+
items.push({ ...metadata, slug });
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
const sorted = items.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
|
|
394
|
+
return latest ? sorted.slice(0, latest) : sorted;
|
|
395
|
+
}
|
|
396
|
+
async function searchContent(bucket, query) {
|
|
397
|
+
const q = query.toLowerCase();
|
|
398
|
+
const results = [];
|
|
399
|
+
const [blogsList, storiesList] = await Promise.all([
|
|
400
|
+
bucket.list({ prefix: "blogs/" }),
|
|
401
|
+
bucket.list({ prefix: "stories/" })
|
|
402
|
+
]);
|
|
403
|
+
for (const item of [...blogsList.objects, ...storiesList.objects]) {
|
|
404
|
+
if (item.key.endsWith(".md")) {
|
|
405
|
+
const obj = await bucket.get(item.key);
|
|
406
|
+
if (obj) {
|
|
407
|
+
const text = await obj.text();
|
|
408
|
+
const { metadata } = parseFrontmatter(text);
|
|
409
|
+
const matchTitle = metadata.title?.toLowerCase().includes(q);
|
|
410
|
+
const matchDesc = metadata.description?.toLowerCase().includes(q);
|
|
411
|
+
const matchTags = metadata.tags?.some((t) => t.toLowerCase().includes(q));
|
|
412
|
+
if (matchTitle || matchDesc || matchTags) {
|
|
413
|
+
results.push(metadata);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
return results;
|
|
419
|
+
}
|
|
298
420
|
function getSessionToken(request) {
|
|
299
421
|
const cookieHeader = request.headers.get("Cookie");
|
|
300
422
|
if (!cookieHeader) return null;
|
|
@@ -399,8 +521,9 @@ async function handleWrite(request, bucket, subpath, env, method) {
|
|
|
399
521
|
options.httpMetadata = { contentType };
|
|
400
522
|
}
|
|
401
523
|
await bucket.put(subpath, request.body, options);
|
|
402
|
-
clearContentCache();
|
|
403
524
|
clearContentCache$1();
|
|
525
|
+
clearContentCache$2();
|
|
526
|
+
clearContentCache();
|
|
404
527
|
return createJSONResponse({ success: true, key: subpath });
|
|
405
528
|
} catch (e) {
|
|
406
529
|
return createErrorResponse("Failed to upload content: " + e.message, 500);
|
|
@@ -409,8 +532,9 @@ async function handleWrite(request, bucket, subpath, env, method) {
|
|
|
409
532
|
if (method === "DELETE" && subpath) {
|
|
410
533
|
try {
|
|
411
534
|
await bucket.delete(subpath);
|
|
412
|
-
clearContentCache();
|
|
413
535
|
clearContentCache$1();
|
|
536
|
+
clearContentCache$2();
|
|
537
|
+
clearContentCache();
|
|
414
538
|
return createJSONResponse({ success: true, key: subpath });
|
|
415
539
|
} catch (e) {
|
|
416
540
|
return createErrorResponse("Failed to delete content: " + e.message, 500);
|
|
@@ -579,123 +703,6 @@ async function handleLogout(request, env) {
|
|
|
579
703
|
}
|
|
580
704
|
});
|
|
581
705
|
}
|
|
582
|
-
const contentCache = new ContentCacheV2(
|
|
583
|
-
5 * 60 * 1e3,
|
|
584
|
-
// TTL: 5 minutes fresh
|
|
585
|
-
true,
|
|
586
|
-
// enabled
|
|
587
|
-
30 * 60 * 1e3
|
|
588
|
-
// SWR TTL: 30 minutes stale window
|
|
589
|
-
);
|
|
590
|
-
function getCachedOrFetch(key, fetchFn) {
|
|
591
|
-
const cached = contentCache.get(key);
|
|
592
|
-
if (cached) {
|
|
593
|
-
if (!cached.stale) {
|
|
594
|
-
return Promise.resolve(cached.data);
|
|
595
|
-
}
|
|
596
|
-
fetchFn().then((data) => {
|
|
597
|
-
contentCache.set(key, data);
|
|
598
|
-
contentCache.refresh(key);
|
|
599
|
-
}).catch(() => {
|
|
600
|
-
});
|
|
601
|
-
return Promise.resolve(cached.data);
|
|
602
|
-
}
|
|
603
|
-
return fetchFn().then((data) => {
|
|
604
|
-
contentCache.set(key, data);
|
|
605
|
-
return data;
|
|
606
|
-
});
|
|
607
|
-
}
|
|
608
|
-
function parseFrontmatter(content) {
|
|
609
|
-
const lines = content.split("\n");
|
|
610
|
-
const metadata = {};
|
|
611
|
-
let contentStart = 0;
|
|
612
|
-
if (lines[0]?.trim() === "---") {
|
|
613
|
-
for (let i = 1; i < lines.length; i++) {
|
|
614
|
-
if (lines[i]?.trim() === "---") {
|
|
615
|
-
contentStart = i + 1;
|
|
616
|
-
break;
|
|
617
|
-
}
|
|
618
|
-
const colonIdx = lines[i].indexOf(":");
|
|
619
|
-
if (colonIdx > 0) {
|
|
620
|
-
const key = lines[i].slice(0, colonIdx).trim();
|
|
621
|
-
let value = lines[i].slice(colonIdx + 1).trim();
|
|
622
|
-
if (value.startsWith("[") && value.endsWith("]")) {
|
|
623
|
-
value = value.slice(1, -1);
|
|
624
|
-
metadata[key] = value.split(",").map((v) => v.trim());
|
|
625
|
-
} else {
|
|
626
|
-
metadata[key] = value;
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
return {
|
|
632
|
-
metadata,
|
|
633
|
-
content: lines.slice(contentStart).join("\n").trim()
|
|
634
|
-
};
|
|
635
|
-
}
|
|
636
|
-
function checkContentBucket(env) {
|
|
637
|
-
if (!env?.CONTENT_BUCKET) {
|
|
638
|
-
return createErrorResponse("Content bucket not configured", 500);
|
|
639
|
-
}
|
|
640
|
-
return null;
|
|
641
|
-
}
|
|
642
|
-
async function fetchContentItem(bucket, type, slug) {
|
|
643
|
-
const mdObj = await bucket.get(`${type}/${slug}.md`);
|
|
644
|
-
const jsonObj = await bucket.get(`${type}/${slug}.json`);
|
|
645
|
-
if (!mdObj && !jsonObj) throw new Error(`${type.slice(0, -1)} not found`);
|
|
646
|
-
let metadata = {};
|
|
647
|
-
if (jsonObj) {
|
|
648
|
-
metadata = await jsonObj.json();
|
|
649
|
-
}
|
|
650
|
-
let content = "";
|
|
651
|
-
if (mdObj) {
|
|
652
|
-
const text = await mdObj.text();
|
|
653
|
-
const parsed = parseFrontmatter(text);
|
|
654
|
-
content = parsed.content;
|
|
655
|
-
metadata = { ...parsed.metadata, ...metadata };
|
|
656
|
-
}
|
|
657
|
-
return { ...metadata, slug, content };
|
|
658
|
-
}
|
|
659
|
-
async function fetchContentList(bucket, type, latest) {
|
|
660
|
-
const list = await bucket.list({ prefix: `${type}/` });
|
|
661
|
-
const items = [];
|
|
662
|
-
for (const item of list.objects) {
|
|
663
|
-
if (item.key.endsWith(".json")) {
|
|
664
|
-
const obj = await bucket.get(item.key);
|
|
665
|
-
if (obj) {
|
|
666
|
-
const metadata = await obj.json();
|
|
667
|
-
const slug = item.key.replace(`${type}/`, "").replace(".json", "");
|
|
668
|
-
items.push({ ...metadata, slug });
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
const sorted = items.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
|
|
673
|
-
return latest ? sorted.slice(0, latest) : sorted;
|
|
674
|
-
}
|
|
675
|
-
async function searchContent(bucket, query) {
|
|
676
|
-
const q = query.toLowerCase();
|
|
677
|
-
const results = [];
|
|
678
|
-
const [blogsList, storiesList] = await Promise.all([
|
|
679
|
-
bucket.list({ prefix: "blogs/" }),
|
|
680
|
-
bucket.list({ prefix: "stories/" })
|
|
681
|
-
]);
|
|
682
|
-
for (const item of [...blogsList.objects, ...storiesList.objects]) {
|
|
683
|
-
if (item.key.endsWith(".md")) {
|
|
684
|
-
const obj = await bucket.get(item.key);
|
|
685
|
-
if (obj) {
|
|
686
|
-
const text = await obj.text();
|
|
687
|
-
const { metadata } = parseFrontmatter(text);
|
|
688
|
-
const matchTitle = metadata.title?.toLowerCase().includes(q);
|
|
689
|
-
const matchDesc = metadata.description?.toLowerCase().includes(q);
|
|
690
|
-
const matchTags = metadata.tags?.some((t) => t.toLowerCase().includes(q));
|
|
691
|
-
if (matchTitle || matchDesc || matchTags) {
|
|
692
|
-
results.push(metadata);
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
return results;
|
|
698
|
-
}
|
|
699
706
|
async function handleBlogs(env, slug, latest) {
|
|
700
707
|
const bucketCheck = checkContentBucket(env);
|
|
701
708
|
if (bucketCheck) return bucketCheck;
|
|
@@ -924,7 +931,7 @@ class WebsiteAPI {
|
|
|
924
931
|
if (!session || session.expiresAt < Date.now()) {
|
|
925
932
|
return this.addAdminCORSHeaders(createErrorResponse("Unauthorized", 401), origin);
|
|
926
933
|
}
|
|
927
|
-
clearContentCache$
|
|
934
|
+
clearContentCache$2();
|
|
928
935
|
return this.addAdminCORSHeaders(new Response(JSON.stringify({ success: true, message: "Cache cleared" }), { status: 200, headers: { "Content-Type": "application/json" } }), origin);
|
|
929
936
|
case "aboutme":
|
|
930
937
|
return this.addAdminCORSHeaders(await handleAboutMe(env), origin);
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A, B, M, R, W, c, a, g, b, d, h, e, r, s, v } from "./chunks/website-api-
|
|
1
|
+
import { A, B, M, R, W, c, a, g, b, d, h, e, r, s, v } from "./chunks/website-api-DBEh24zq.js";
|
|
2
2
|
import { WebsitePrerender } from "./prerender.js";
|
|
3
3
|
import { A as A2, a as a2, b as b2, c as c2, d as d2, e as e2, f, g as g2, h as h2, i, B as B2, F, M as M2, j, S, k } from "./chunks/index-DAog9TQE.js";
|
|
4
4
|
import { S as S2, g as g3, i as i2, r as r2 } from "./chunks/site-store-CGV9c2DI.js";
|
package/package.json
CHANGED