@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":"AAoBA,wBAAsB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAqElG"}
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-Cy2kZ0dC.js";
2
- import { A, B, M, R, c, a, g, b, d, h, e, r, s, v } from "./chunks/website-api-Cy2kZ0dC.js";
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$1() {
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$1();
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-Cy2kZ0dC.js";
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leadertechie/personal-site-kit",
3
- "version": "0.1.0-alpha.17",
3
+ "version": "0.1.0-alpha.18",
4
4
  "type": "module",
5
5
  "description": "A high-performance personal website engine for Cloudflare Workers and R2",
6
6
  "repository": {