]> git.otsuka.systems Git - cotsuka.github.io/commitdiff
improve types and schemas
authorCameron Otsuka <cameron@otsuka.haus>
Wed, 17 Dec 2025 01:17:47 +0000 (17:17 -0800)
committerCameron Otsuka <cameron@otsuka.haus>
Wed, 17 Dec 2025 01:17:47 +0000 (17:17 -0800)
98 files changed:
bun.lock
content/podcasts/build-weekly-roundup-2025-04.md [moved from content/podcasts/2025-04.md with 91% similarity]
content/podcasts/build-weekly-roundup-2025-05.md [moved from content/podcasts/2025-05.md with 88% similarity]
content/podcasts/build-weekly-roundup-2025-06.mdx [moved from content/podcasts/2025-06.mdx with 92% similarity]
content/podcasts/build-weekly-roundup-2025-07.mdx [moved from content/podcasts/2025-07.mdx with 93% similarity]
content/podcasts/build-weekly-roundup-2025-08.mdx [moved from content/podcasts/2025-08.mdx with 91% similarity]
content/podcasts/build-weekly-roundup-2025-11.mdx [moved from content/podcasts/2025-11.mdx with 93% similarity]
content/podcasts/build-weekly-roundup-2025-12.mdx [moved from content/podcasts/2025-12.mdx with 92% similarity]
content/podcasts/build-weekly-roundup-2025-14.mdx [moved from content/podcasts/2025-14.mdx with 92% similarity]
content/podcasts/build-weekly-roundup-2025-15.mdx [moved from content/podcasts/2025-15.mdx with 92% similarity]
content/podcasts/build-weekly-roundup-2025-17.mdx [moved from content/podcasts/2025-17.mdx with 92% similarity]
content/podcasts/build-weekly-roundup-2025-18.mdx [moved from content/podcasts/2025-18.mdx with 93% similarity]
content/podcasts/build-weekly-roundup-2025-19.mdx [moved from content/podcasts/2025-19.mdx with 92% similarity]
content/podcasts/build-weekly-roundup-2025-20.mdx [moved from content/podcasts/2025-20.mdx with 94% similarity]
content/podcasts/build-weekly-roundup-2025-21.mdx [moved from content/podcasts/2025-21.mdx with 92% similarity]
content/podcasts/build-weekly-roundup-2025-23.mdx [moved from content/podcasts/2025-23.mdx with 93% similarity]
content/podcasts/build-weekly-roundup-2025-24.mdx [moved from content/podcasts/2025-24.mdx with 92% similarity]
content/podcasts/build-weekly-roundup-2025-25.mdx [moved from content/podcasts/2025-25.mdx with 92% similarity]
content/podcasts/build-weekly-roundup-2025-26.mdx [moved from content/podcasts/2025-26.mdx with 92% similarity]
content/podcasts/build-weekly-roundup-2025-29.mdx [moved from content/podcasts/2025-29.mdx with 92% similarity]
content/podcasts/build-weekly-roundup-2025-30.mdx [moved from content/podcasts/2025-30.mdx with 93% similarity]
content/podcasts/build-weekly-roundup-2025-33.mdx [moved from content/podcasts/2025-33.mdx with 92% similarity]
content/podcasts/build-weekly-roundup-2025-36.mdx [moved from content/podcasts/2025-36.mdx with 93% similarity]
content/podcasts/build-weekly-roundup-2025-37.mdx [moved from content/podcasts/2025-37.mdx with 92% similarity]
content/podcasts/build-weekly-roundup-2025-38.mdx [moved from content/podcasts/2025-38.mdx with 92% similarity]
content/podcasts/build-weekly-roundup-2025-39.mdx [moved from content/podcasts/2025-39.mdx with 92% similarity]
content/podcasts/build-weekly-roundup-2025-40.mdx [moved from content/podcasts/2025-40.mdx with 92% similarity]
content/podcasts/build-weekly-roundup-2025-41.mdx [moved from content/podcasts/2025-41.mdx with 92% similarity]
content/podcasts/build-weekly-roundup-2025-42.mdx [moved from content/podcasts/2025-42.mdx with 92% similarity]
content/podcasts/build-weekly-roundup-2025-43.mdx [moved from content/podcasts/2025-43.mdx with 92% similarity]
content/podcasts/build-weekly-roundup-2025-44.mdx [moved from content/podcasts/2025-44.mdx with 92% similarity]
content/podcasts/build-weekly-roundup-2025-45.mdx [moved from content/podcasts/2025-45.mdx with 92% similarity]
content/podcasts/build-weekly-roundup-2025-46.mdx [moved from content/podcasts/2025-46.mdx with 92% similarity]
content/podcasts/build-weekly-roundup-2025-47.mdx [moved from content/podcasts/2025-47.mdx with 92% similarity]
content/podcasts/build-weekly-roundup-2025-48.mdx [moved from content/podcasts/2025-48.mdx with 92% similarity]
content/podcasts/build-weekly-roundup-2025-49.mdx [moved from content/podcasts/2025-49.mdx with 92% similarity]
content/podcasts/build-weekly-roundup-2025-50.mdx [moved from content/podcasts/2025-50.mdx with 92% similarity]
content/reviews/28-days-later.md
content/reviews/a-complete-unknown.mdx
content/reviews/bugonia.md
content/reviews/burning.md
content/reviews/casino-royale.md
content/reviews/caught-stealing.md
content/reviews/challengers.md
content/reviews/conclave.md
content/reviews/death-becomes-her.md
content/reviews/den-of-thieves-pantera.md
content/reviews/f1-the-movie.md
content/reviews/fallen-angels/index.mdx
content/reviews/hunchback-of-notre-dame.md
content/reviews/its-whats-inside.md
content/reviews/jurassic-park.md
content/reviews/materialists.md
content/reviews/mulholland-drive.md
content/reviews/nosferatu.md
content/reviews/one-battle-after-another.mdx
content/reviews/perfect-days.md
content/reviews/problemista.md
content/reviews/sinners.md
content/reviews/star-wars-episode-iii-revenge-of-the-sith.md
content/reviews/subservience.md
content/reviews/superman.mdx
content/reviews/the-apprentice.md
content/reviews/the-boy-and-the-heron.md
content/reviews/the-godfather.md
content/reviews/the-lord-of-the-rings-the-fellowship-of-the-ring.md
content/reviews/wake up dead man.md
content/reviews/warfare.md
content/reviews/wicked-for-good.mdx
content/reviews/wicked.md
package.json
src/components/footer.astro
src/components/head/article.astro
src/components/head/base.astro
src/components/metadata.astro
src/components/navigation.astro
src/components/ratingdistribution/component.astro
src/components/ui/rating.astro
src/components/youtube.astro
src/content.config.ts
src/pages/articles/[date]-[id]/index.astro
src/pages/articles/[date]-[id]/opengraph.png.ts
src/pages/articles/index.astro
src/pages/feed.xml.ts
src/pages/index.astro
src/pages/podcasts/[id]/index.astro [moved from src/pages/podcasts/[show]-[id]/index.astro with 80% similarity]
src/pages/podcasts/[id]/opengraph.png.ts [moved from src/pages/podcasts/[show]-[id]/opengraph.png.ts with 69% similarity]
src/pages/podcasts/index.astro
src/pages/reviews/[category]/[id]/index.astro [moved from src/pages/reviews/[type]/[id]/index.astro with 92% similarity]
src/pages/reviews/[category]/[id]/opengraph.png.ts [moved from src/pages/reviews/[type]/[id]/opengraph.png.ts with 79% similarity]
src/pages/reviews/index.astro
src/utils/createSlug.ts
src/utils/formatDate.ts
src/utils/generateContentUrl.ts
src/utils/generateOpenGraphImage.ts
src/utils/generateStarRating.ts
src/utils/globals.ts
src/utils/sortByDate.ts

index bf59ce89d746f27f58857cc599e5e865d42ea07f..6cf3332262fa0b1e8041d34f546a53d1ddbe4f70 100644 (file)
--- a/bun.lock
+++ b/bun.lock
         "@fontsource-variable/source-serif-4": "^5.2.9",
         "@iconify-json/mdi": "^1.2.3",
         "@vercel/og": "^0.8.5",
-        "astro": "5.16.3",
+        "astro": "5.16.5",
         "astro-icon": "^1.1.5",
-        "react": "^19.2.0",
-        "react-dom": "^19.2.0",
+        "react": "^19.2.3",
+        "react-dom": "^19.2.3",
         "recharts": "^3.5.1",
       },
       "devDependencies": {
-        "@types/bun": "^1.3.3",
+        "@types/bun": "^1.3.4",
         "@types/react": "^19.2.7",
         "@types/react-dom": "^19.2.3",
       },
 
     "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.43.0", "", { "os": "win32", "cpu": "x64" }, "sha512-SnGhLiE5rlK0ofq8kzuDkM0g7FN1s5VYY+YSMTibP7CqShxCQvqtNxTARS4xX4PFJfHjG0ZQYX9iGzI3FQh5Aw=="],
 
-    "@shikijs/core": ["@shikijs/core@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-8TOG6yG557q+fMsSVa8nkEDOZNTSxjbbR8l6lF2gyr6Np+jrPlslqDxQkN6rMXCECQ3isNPZAGszAfYoJOPGlg=="],
+    "@shikijs/core": ["@shikijs/core@3.20.0", "", { "dependencies": { "@shikijs/types": "3.20.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-f2ED7HYV4JEk827mtMDwe/yQ25pRiXZmtHjWF8uzZKuKiEsJR7Ce1nuQ+HhV9FzDcbIo4ObBCD9GPTzNuy9S1g=="],
 
-    "@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-ZedbOFpopibdLmvTz2sJPJgns8Xvyabe2QbmqMTz07kt1pTzfEvKZc5IqPVO/XFiEbbNyaOpjPBkkr1vlwS+qg=="],
+    "@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.20.0", "", { "dependencies": { "@shikijs/types": "3.20.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-OFx8fHAZuk7I42Z9YAdZ95To6jDePQ9Rnfbw9uSRTSbBhYBp1kEOKv/3jOimcj3VRUKusDYM6DswLauwfhboLg=="],
 
-    "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-HnqFsV11skAHvOArMZdLBZZApRSYS4LSztk2K3016Y9VCyZISnlYUYsL2hzlS7tPqKHvNqmI5JSUJZprXloMvA=="],
+    "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.20.0", "", { "dependencies": { "@shikijs/types": "3.20.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-Yx3gy7xLzM0ZOjqoxciHjA7dAt5tyzJE3L4uQoM83agahy+PlW244XJSrmJRSBvGYELDhYXPacD4R/cauV5bzQ=="],
 
-    "@shikijs/langs": ["@shikijs/langs@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0" } }, "sha512-WpRvEFvkVvO65uKYW4Rzxs+IG0gToyM8SARQMtGGsH4GDMNZrr60qdggXrFOsdfOVssG/QQGEl3FnJ3EZ+8w8A=="],
+    "@shikijs/langs": ["@shikijs/langs@3.20.0", "", { "dependencies": { "@shikijs/types": "3.20.0" } }, "sha512-le+bssCxcSHrygCWuOrYJHvjus6zhQ2K7q/0mgjiffRbkhM4o1EWu2m+29l0yEsHDbWaWPNnDUTRVVBvBBeKaA=="],
 
-    "@shikijs/themes": ["@shikijs/themes@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0" } }, "sha512-8ow2zWb1IDvCKjYb0KiLNrK4offFdkfNVPXb1OZykpLCzRU6j+efkY+Y7VQjNlNFXonSw+4AOdGYtmqykDbRiQ=="],
+    "@shikijs/themes": ["@shikijs/themes@3.20.0", "", { "dependencies": { "@shikijs/types": "3.20.0" } }, "sha512-U1NSU7Sl26Q7ErRvJUouArxfM2euWqq1xaSrbqMu2iqa+tSp0D1Yah8216sDYbdDHw4C8b75UpE65eWorm2erQ=="],
 
-    "@shikijs/types": ["@shikijs/types@3.15.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-BnP+y/EQnhihgHy4oIAN+6FFtmfTekwOLsQbRw9hOKwqgNy8Bdsjq8B05oAt/ZgvIWWFrshV71ytOrlPfYjIJw=="],
+    "@shikijs/types": ["@shikijs/types@3.20.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-lhYAATn10nkZcBQ0BlzSbJA3wcmL5MXUUF8d2Zzon6saZDlToKaiRX60n2+ZaHJCmXEcZRWNzn+k9vplr8Jhsw=="],
 
     "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="],
 
 
     "@types/babel__traverse": ["@types/babel__traverse@7.20.7", "", { "dependencies": { "@babel/types": "^7.20.7" } }, "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng=="],
 
-    "@types/bun": ["@types/bun@1.3.3", "", { "dependencies": { "bun-types": "1.3.3" } }, "sha512-ogrKbJ2X5N0kWLLFKeytG0eHDleBYtngtlbu9cyBKFtNL3cnpDZkNdQj8flVf6WTZUX5ulI9AY1oa7ljhSrp+g=="],
+    "@types/bun": ["@types/bun@1.3.4", "", { "dependencies": { "bun-types": "1.3.4" } }, "sha512-EEPTKXHP+zKGPkhRLv+HI0UEX8/o+65hqARxLy8Ov5rIxMBPNTjeZww00CIihrIQGEQBYg+0roO5qOnS/7boGA=="],
 
     "@types/d3-array": ["@types/d3-array@3.2.1", "", {}, "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg=="],
 
 
     "astring": ["astring@1.9.0", "", { "bin": { "astring": "bin/astring" } }, "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg=="],
 
-    "astro": ["astro@5.16.3", "", { "dependencies": { "@astrojs/compiler": "^2.13.0", "@astrojs/internal-helpers": "0.7.5", "@astrojs/markdown-remark": "6.3.9", "@astrojs/telemetry": "3.3.0", "@capsizecss/unpack": "^3.0.1", "@oslojs/encoding": "^1.1.0", "@rollup/pluginutils": "^5.3.0", "acorn": "^8.15.0", "aria-query": "^5.3.2", "axobject-query": "^4.1.0", "boxen": "8.0.1", "ci-info": "^4.3.1", "clsx": "^2.1.1", "common-ancestor-path": "^1.0.1", "cookie": "^1.0.2", "cssesc": "^3.0.0", "debug": "^4.4.3", "deterministic-object-hash": "^2.0.2", "devalue": "^5.5.0", "diff": "^5.2.0", "dlv": "^1.1.3", "dset": "^3.1.4", "es-module-lexer": "^1.7.0", "esbuild": "^0.25.0", "estree-walker": "^3.0.3", "flattie": "^1.1.1", "fontace": "~0.3.1", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", "http-cache-semantics": "^4.2.0", "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.1", "magic-string": "^0.30.21", "magicast": "^0.5.1", "mrmime": "^2.0.1", "neotraverse": "^0.6.18", "p-limit": "^6.2.0", "p-queue": "^8.1.1", "package-manager-detector": "^1.5.0", "piccolore": "^0.1.3", "picomatch": "^4.0.3", "prompts": "^2.4.2", "rehype": "^13.0.2", "semver": "^7.7.3", "shiki": "^3.15.0", "smol-toml": "^1.5.2", "svgo": "^4.0.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tsconfck": "^3.1.6", "ultrahtml": "^1.6.0", "unifont": "~0.6.0", "unist-util-visit": "^5.0.0", "unstorage": "^1.17.3", "vfile": "^6.0.3", "vite": "^6.4.1", "vitefu": "^1.1.1", "xxhash-wasm": "^1.1.0", "yargs-parser": "^21.1.1", "yocto-spinner": "^0.2.3", "zod": "^3.25.76", "zod-to-json-schema": "^3.25.0", "zod-to-ts": "^1.2.0" }, "optionalDependencies": { "sharp": "^0.34.0" }, "bin": { "astro": "astro.js" } }, "sha512-KzDk41F9Dspf5fM/Ls4XZhV4/csjJcWBrlenbnp5V3NGwU1zEaJz/HIyrdKdf5yw+FgwCeD2+Yos1Xkx9gnI0A=="],
+    "astro": ["astro@5.16.5", "", { "dependencies": { "@astrojs/compiler": "^2.13.0", "@astrojs/internal-helpers": "0.7.5", "@astrojs/markdown-remark": "6.3.10", "@astrojs/telemetry": "3.3.0", "@capsizecss/unpack": "^3.0.1", "@oslojs/encoding": "^1.1.0", "@rollup/pluginutils": "^5.3.0", "acorn": "^8.15.0", "aria-query": "^5.3.2", "axobject-query": "^4.1.0", "boxen": "8.0.1", "ci-info": "^4.3.1", "clsx": "^2.1.1", "common-ancestor-path": "^1.0.1", "cookie": "^1.0.2", "cssesc": "^3.0.0", "debug": "^4.4.3", "deterministic-object-hash": "^2.0.2", "devalue": "^5.5.0", "diff": "^5.2.0", "dlv": "^1.1.3", "dset": "^3.1.4", "es-module-lexer": "^1.7.0", "esbuild": "^0.25.0", "estree-walker": "^3.0.3", "flattie": "^1.1.1", "fontace": "~0.3.1", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", "http-cache-semantics": "^4.2.0", "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.1", "magic-string": "^0.30.21", "magicast": "^0.5.1", "mrmime": "^2.0.1", "neotraverse": "^0.6.18", "p-limit": "^6.2.0", "p-queue": "^8.1.1", "package-manager-detector": "^1.5.0", "piccolore": "^0.1.3", "picomatch": "^4.0.3", "prompts": "^2.4.2", "rehype": "^13.0.2", "semver": "^7.7.3", "shiki": "^3.15.0", "smol-toml": "^1.5.2", "svgo": "^4.0.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tsconfck": "^3.1.6", "ultrahtml": "^1.6.0", "unifont": "~0.6.0", "unist-util-visit": "^5.0.0", "unstorage": "^1.17.3", "vfile": "^6.0.3", "vite": "^6.4.1", "vitefu": "^1.1.1", "xxhash-wasm": "^1.1.0", "yargs-parser": "^21.1.1", "yocto-spinner": "^0.2.3", "zod": "^3.25.76", "zod-to-json-schema": "^3.25.0", "zod-to-ts": "^1.2.0" }, "optionalDependencies": { "sharp": "^0.34.0" }, "bin": { "astro": "astro.js" } }, "sha512-QeuM4xzTR0QuXFDNlGVW0BW7rcquKFIkylaPeM4ufii0/RRiPTYtwxDYVZ3KfiMRuuc+nbLD0214kMKTvz/yvQ=="],
 
     "astro-icon": ["astro-icon@1.1.5", "", { "dependencies": { "@iconify/tools": "^4.0.5", "@iconify/types": "^2.0.0", "@iconify/utils": "^2.1.30" } }, "sha512-CJYS5nWOw9jz4RpGWmzNQY7D0y2ZZacH7atL2K9DeJXJVaz7/5WrxeyIxO8KASk1jCM96Q4LjRx/F3R+InjJrw=="],
 
 
     "buffer-crc32": ["buffer-crc32@0.2.13", "", {}, "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ=="],
 
-    "bun-types": ["bun-types@1.3.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-z3Xwlg7j2l9JY27x5Qn3Wlyos8YAp0kKRlrePAOjgjMGS5IG6E7Jnlx736vH9UVI4wUICwwhC9anYL++XeOgTQ=="],
+    "bun-types": ["bun-types@1.3.4", "", { "dependencies": { "@types/node": "*" } }, "sha512-5ua817+BZPZOlNaRgGBpZJOSAQ9RQ17pkwPD0yR7CfJg+r8DgIILByFifDTa+IPDDxzf5VNhtNlcKqFzDgJvlQ=="],
 
     "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
 
 
     "oniguruma-parser": ["oniguruma-parser@0.12.1", "", {}, "sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w=="],
 
-    "oniguruma-to-es": ["oniguruma-to-es@4.3.3", "", { "dependencies": { "oniguruma-parser": "^0.12.1", "regex": "^6.0.1", "regex-recursion": "^6.0.2" } }, "sha512-rPiZhzC3wXwE59YQMRDodUwwT9FZ9nNBwQQfsd1wfdtlKEyCdRV0avrTcSZ5xlIvGRVPd/cx6ZN45ECmS39xvg=="],
+    "oniguruma-to-es": ["oniguruma-to-es@4.3.4", "", { "dependencies": { "oniguruma-parser": "^0.12.1", "regex": "^6.0.1", "regex-recursion": "^6.0.2" } }, "sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA=="],
 
     "p-limit": ["p-limit@6.2.0", "", { "dependencies": { "yocto-queue": "^1.1.1" } }, "sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA=="],
 
 
     "radix3": ["radix3@1.1.2", "", {}, "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA=="],
 
-    "react": ["react@19.2.0", "", {}, "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ=="],
+    "react": ["react@19.2.3", "", {}, "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA=="],
 
-    "react-dom": ["react-dom@19.2.0", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.0" } }, "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ=="],
+    "react-dom": ["react-dom@19.2.3", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.3" } }, "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg=="],
 
     "react-is": ["react-is@19.1.0", "", {}, "sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg=="],
 
 
     "sharp": ["sharp@0.34.3", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.4", "semver": "^7.7.2" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.3", "@img/sharp-darwin-x64": "0.34.3", "@img/sharp-libvips-darwin-arm64": "1.2.0", "@img/sharp-libvips-darwin-x64": "1.2.0", "@img/sharp-libvips-linux-arm": "1.2.0", "@img/sharp-libvips-linux-arm64": "1.2.0", "@img/sharp-libvips-linux-ppc64": "1.2.0", "@img/sharp-libvips-linux-s390x": "1.2.0", "@img/sharp-libvips-linux-x64": "1.2.0", "@img/sharp-libvips-linuxmusl-arm64": "1.2.0", "@img/sharp-libvips-linuxmusl-x64": "1.2.0", "@img/sharp-linux-arm": "0.34.3", "@img/sharp-linux-arm64": "0.34.3", "@img/sharp-linux-ppc64": "0.34.3", "@img/sharp-linux-s390x": "0.34.3", "@img/sharp-linux-x64": "0.34.3", "@img/sharp-linuxmusl-arm64": "0.34.3", "@img/sharp-linuxmusl-x64": "0.34.3", "@img/sharp-wasm32": "0.34.3", "@img/sharp-win32-arm64": "0.34.3", "@img/sharp-win32-ia32": "0.34.3", "@img/sharp-win32-x64": "0.34.3" } }, "sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg=="],
 
-    "shiki": ["shiki@3.15.0", "", { "dependencies": { "@shikijs/core": "3.15.0", "@shikijs/engine-javascript": "3.15.0", "@shikijs/engine-oniguruma": "3.15.0", "@shikijs/langs": "3.15.0", "@shikijs/themes": "3.15.0", "@shikijs/types": "3.15.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-kLdkY6iV3dYbtPwS9KXU7mjfmDm25f5m0IPNFnaXO7TBPcvbUOY72PYXSuSqDzwp+vlH/d7MXpHlKO/x+QoLXw=="],
+    "shiki": ["shiki@3.20.0", "", { "dependencies": { "@shikijs/core": "3.20.0", "@shikijs/engine-javascript": "3.20.0", "@shikijs/engine-oniguruma": "3.20.0", "@shikijs/langs": "3.20.0", "@shikijs/themes": "3.20.0", "@shikijs/types": "3.20.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-kgCOlsnyWb+p0WU+01RjkCH+eBVsjL1jOwUYWv0YDWkM2/A46+LDKVs5yZCUXjJG6bj4ndFoAg5iLIIue6dulg=="],
 
     "simple-swizzle": ["simple-swizzle@0.2.2", "", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg=="],
 
 
     "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
 
+    "astro/@astrojs/markdown-remark": ["@astrojs/markdown-remark@6.3.10", "", { "dependencies": { "@astrojs/internal-helpers": "0.7.5", "@astrojs/prism": "3.3.0", "github-slugger": "^2.0.0", "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.1", "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", "rehype-stringify": "^10.0.1", "remark-gfm": "^4.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-smartypants": "^3.0.2", "shiki": "^3.19.0", "smol-toml": "^1.5.2", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.2", "vfile": "^6.0.3" } }, "sha512-kk4HeYR6AcnzC4QV8iSlOfh+N8TZ3MEStxPyenyCtemqn8IpEATBFMTJcfrNW32dgpt6MY3oCkMM/Tv3/I4G3A=="],
+
     "brotli/base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
 
     "csso/css-tree": ["css-tree@2.2.1", "", { "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" } }, "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA=="],
similarity index 91%
rename from content/podcasts/2025-04.md
rename to content/podcasts/build-weekly-roundup-2025-04.md
index d6d4954571e4625da3176a555ee7053420ce798a..c2dff67df03ff4d84d07525c6ee6514abef7d7dc 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: we're ripping off-the-cuff about dollar rallying, rates, stargate, and deepseek. listen in 👇
 date: 2025-01-23
 modified: 2025-06-19
-show: Build Weekly Roundup
-description: "2025 Week #4"
+description: "Build Weekly Roundup - 2025 Week #4"
 tags:
 - ai
 - macro
similarity index 88%
rename from content/podcasts/2025-05.md
rename to content/podcasts/build-weekly-roundup-2025-05.md
index 516dc0c39540debe0f9c05c117ba7552820ca9bb..efbe9850e3750a3d9770878269705d94deca24b0 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: Yield curve updates, looking forward to Yen meeting, more DeepSeek analysis
 date: 2025-01-30
 modified: 2025-06-19
-show: Build Weekly Roundup
-description: "2025 Week #5"
+description: "Build Weekly Roundup - 2025 Week #5"
 tags:
 - ai
 - macro
similarity index 92%
rename from content/podcasts/2025-06.mdx
rename to content/podcasts/build-weekly-roundup-2025-06.mdx
index 1e22044a430c508a6b07dc9543d3f7b63316c6e8..fe536074ae5c139865ced9ca65e54418bee7575c 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: Listen in as we break down Treasury yields, bond liquidity, potential regulatory changes, Bitcoin's mempools, and alternative investments 👇
 date: 2025-02-06
 modified: 2025-10-24
-show: Build Weekly Roundup
-description: "2025 Week #6"
+description: "Build Weekly Roundup - 2025 Week #6"
 tags:
 - bitcoin
 - macro
similarity index 93%
rename from content/podcasts/2025-07.mdx
rename to content/podcasts/build-weekly-roundup-2025-07.mdx
index cc05fc0b8549cedb0edc7c340f97d59cbec24e25..ed85a58599e220313013704a9b1b273df468562c 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: 🚨 the penny peg has broken, new 6-week t-bills, ukraine peace talks, and more
 date: 2025-02-13
 modified: 2025-10-24
-show: Build Weekly Roundup
-description: "2025 Week #7"
+description: "Build Weekly Roundup - 2025 Week #7"
 tags:
 - macro
 posse:
similarity index 91%
rename from content/podcasts/2025-08.mdx
rename to content/podcasts/build-weekly-roundup-2025-08.mdx
index 0897dffeb175f623a7589e06a4a028546239dfb2..472ddf9ebc06786f7554c990eedfb58b1fd0ce38 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: Talking DOGE cuts 🐶
 date: 2025-02-20
 modified: 2025-06-06
-show: Build Weekly Roundup
-description: "2025 Week #8"
+description: "Build Weekly Roundup - 2025 Week #8"
 tags:
 - macro
 - bitcoin
similarity index 93%
rename from content/podcasts/2025-11.mdx
rename to content/podcasts/build-weekly-roundup-2025-11.mdx
index 0734a4c1e590c648c4bb49f8aeb2cdd7e3a3e76b..912cc45c3cccb5d6e3232c43ead9f9b2a1b72830 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: Fork in the road for Treasury yields
 date: 2025-03-13
 modified: 2025-06-06
-show: Build Weekly Roundup
-description: "2025 Week #11"
+description: "Build Weekly Roundup - 2025 Week #11"
 tags:
 - macro
 - bitcoin
similarity index 92%
rename from content/podcasts/2025-12.mdx
rename to content/podcasts/build-weekly-roundup-2025-12.mdx
index 3752b01fbf164b5b9ab223338ed1112144dc6bc1..3eeca58588f61a65fc0b3b641f1d5ae1c7958f68 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: Post-FOMC Landscape and the EU Savings & Investments Union
 date: 2025-03-20
 modified: 2025-06-06
-show: Build Weekly Roundup
-description: "2025 Week #12"
+description: "Build Weekly Roundup - 2025 Week #12"
 tags:
 - macro
 posse:
similarity index 92%
rename from content/podcasts/2025-14.mdx
rename to content/podcasts/build-weekly-roundup-2025-14.mdx
index ef93ee7e38e0e68e3c3ff5705154093554affe3d..5d76477650518f74532ee6bfe7f2a566c6f6d897 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: Liberation Day in America
 date: 2025-04-03
 modified: 2025-06-06
-show: Build Weekly Roundup
-description: "2025 Week #14"
+description: "Build Weekly Roundup - 2025 Week #14"
 tags:
 - macro
 posse:
similarity index 92%
rename from content/podcasts/2025-15.mdx
rename to content/podcasts/build-weekly-roundup-2025-15.mdx
index 2ce1a5db98acdc6495762e9941bcff4b8cdda987..38c5cab4718a2dc4c8132da36cd59a72ab2951fc 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: Tariffs pack a wallop
 date: 2025-04-10
 modified: 2025-06-06
-show: Build Weekly Roundup
-description: "2025 Week #15"
+description: "Build Weekly Roundup - 2025 Week #15"
 tags:
 - macro
 posse:
similarity index 92%
rename from content/podcasts/2025-17.mdx
rename to content/podcasts/build-weekly-roundup-2025-17.mdx
index 3a606df77de041756445c9dedc32603aad03db25..0ed7fbf8328bba40c2b82497522e03ebc6296204 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: Retail rushes for gold
 date: 2025-04-25
 modified: 2025-06-06
-show: Build Weekly Roundup
-description: "2025 Week #17"
+description: "Build Weekly Roundup - 2025 Week #17"
 tags:
 - macro
 - bitcoin
similarity index 93%
rename from content/podcasts/2025-18.mdx
rename to content/podcasts/build-weekly-roundup-2025-18.mdx
index 0cfde394b11816ff6f2ef6519df64c6bbca0287f..0099fa315f7c02bbf51fb552a0dfbc84fe35e004 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: The Art of the (Ukraine) Deal
 date: 2025-05-01
 modified: 2025-06-06
-show: Build Weekly Roundup
-description: "2025 Week #18"
+description: "Build Weekly Roundup - 2025 Week #18"
 tags:
 - macro
 - bitcoin
similarity index 92%
rename from content/podcasts/2025-19.mdx
rename to content/podcasts/build-weekly-roundup-2025-19.mdx
index 18fd324d9047ebebaf8185eca62cc2ff6d2121e5..861fce9cfd5b19c32af9085c6ab802f9c89a79eb 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: Hong Kong Dollar Squeeze
 date: 2025-05-08
 modified: 2025-06-06
-show: Build Weekly Roundup
-description: "2025 Week #19"
+description: "Build Weekly Roundup - 2025 Week #19"
 tags:
 - macro
 - bitcoin
similarity index 94%
rename from content/podcasts/2025-20.mdx
rename to content/podcasts/build-weekly-roundup-2025-20.mdx
index bcf407707facc47f842d60548c30d0e83c3994af..568a85fd58c0de96254051cd072ffb7305037560 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: Not Your Father's Recession
 date: 2025-05-15
 modified: 2025-06-06
-show: Build Weekly Roundup
-description: "2025 Week #20"
+description: "Build Weekly Roundup - 2025 Week #20"
 tags:
 - macro
 posse:
similarity index 92%
rename from content/podcasts/2025-21.mdx
rename to content/podcasts/build-weekly-roundup-2025-21.mdx
index e1a9e1dbeb03dc416c6415c69154e478cac36aef..219926be9dcfbaa688d77bcb541b15408d903d59 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: A Pivotal Week
 date: 2025-05-22
 modified: 2025-06-06
-show: Build Weekly Roundup
-description: "2025 Week #21"
+description: "Build Weekly Roundup - 2025 Week #21"
 tags:
 - macro
 posse:
similarity index 93%
rename from content/podcasts/2025-23.mdx
rename to content/podcasts/build-weekly-roundup-2025-23.mdx
index 0fcb7f3be59b367cee874a9af3ea5b6b35977c90..683d98e101901e60f4f8b4d887e2921b317be30a 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: JPM Bends the Knee to Bitcoin
 date: 2025-06-06
 modified: 2025-06-06
-show: Build Weekly Roundup
-description: "2025 Week #23"
+description: "Build Weekly Roundup - 2025 Week #23"
 tags:
 - macro
 - bitcoin
similarity index 92%
rename from content/podcasts/2025-24.mdx
rename to content/podcasts/build-weekly-roundup-2025-24.mdx
index 42d7849e2e0eb43f64b5d5aa941f89ec0f93424f..6e3fbba61b99350b9f5f68d1449299bc6c1604ab 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: Last Chance to Hit the Exit?
 date: 2025-06-12
 modified: 2025-06-18
-show: Build Weekly Roundup
-description: "2025 Week #24"
+description: "Build Weekly Roundup - 2025 Week #24"
 tags:
 - macro
 posse:
similarity index 92%
rename from content/podcasts/2025-25.mdx
rename to content/podcasts/build-weekly-roundup-2025-25.mdx
index c1b26bc23fd2f4a4800313bb5c92ff3340074489..4e4c89d420944d0e148282a56e21e387da7a7c3d 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: Battle of Fordow
 date: 2025-06-18
 modified: 2025-06-18
-show: Build Weekly Roundup
-description: "2025 Week #25"
+description: "Build Weekly Roundup - 2025 Week #25"
 tags:
 - macro
 - bitcoin
similarity index 92%
rename from content/podcasts/2025-26.mdx
rename to content/podcasts/build-weekly-roundup-2025-26.mdx
index 49d7877deb94f59e0dc39b443d2da79000a8ab67..92d8e0c2e7864472db3a9eff9020d1fe495d9e13 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: Rebalance of Power
 date: 2025-06-26
 modified: 2025-07-01
-show: Build Weekly Roundup
-description: "2025 Week #26"
+description: "Build Weekly Roundup - 2025 Week #26"
 tags:
 - macro
 - bitcoin
similarity index 92%
rename from content/podcasts/2025-29.mdx
rename to content/podcasts/build-weekly-roundup-2025-29.mdx
index 3a3447630decc5ab4d07b03ce7b85d69538ab8a0..bfc832fd18cace17172d83fc6352e90a4f1f82b9 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: Monetary Policy Disarray
 date: 2025-07-17
 modified: 2025-07-17
-show: Build Weekly Roundup
-description: "2025 Week #29"
+description: "Build Weekly Roundup - 2025 Week #29"
 tags:
 - macro
 - bitcoin
similarity index 93%
rename from content/podcasts/2025-30.mdx
rename to content/podcasts/build-weekly-roundup-2025-30.mdx
index ce310271b9886066e54be69636a57280efd132a9..7cdd5c2260d6b67c11e72eba2551585c3a124204 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: Rate Shortcut Contractors, Inc.
 date: 2025-07-25
 modified: 2025-07-25
-show: Build Weekly Roundup
-description: "2025 Week #30"
+description: "Build Weekly Roundup - 2025 Week #30"
 tags:
 - macro
 posse:
similarity index 92%
rename from content/podcasts/2025-33.mdx
rename to content/podcasts/build-weekly-roundup-2025-33.mdx
index d1b8ba17c0d794faa4a331452fc8525cd88d390a..26a1abf39976e4c3996ad539fe423e625a7eef59 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: PPI Blowout
 date: 2025-08-15
 modified: 2025-08-17
-show: Build Weekly Roundup
-description: "2025 Week #33"
+description: "Build Weekly Roundup - 2025 Week #33"
 tags:
 - macro
 posse:
similarity index 93%
rename from content/podcasts/2025-36.mdx
rename to content/podcasts/build-weekly-roundup-2025-36.mdx
index d60c1dad22e578de788be9d254e61cf113e6fce8..3247c60a3753683c317a0fe771c7586657108dcb 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: Money, Credit and Asset Prices
 date: 2025-09-08
 modified: 2025-09-09
-show: Build Weekly Roundup
-description: "2025 Week #36"
+description: "Build Weekly Roundup - 2025 Week #36"
 tags:
 - macro
 posse:
similarity index 92%
rename from content/podcasts/2025-37.mdx
rename to content/podcasts/build-weekly-roundup-2025-37.mdx
index b5868edc090f03fda209c2613a68d37bcb54c830..6d226847362d1a534d23ff06af062eed77195496 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: Climbing the Escalatory Ladder
 date: 2025-09-11
 modified: 2025-09-12
-show: Build Weekly Roundup
-description: "2025 Week #37"
+description: "Build Weekly Roundup - 2025 Week #37"
 tags:
 - macro
 posse:
similarity index 92%
rename from content/podcasts/2025-38.mdx
rename to content/podcasts/build-weekly-roundup-2025-38.mdx
index 1d2ae06cb6198e51fb06df422dac8e05dceec290..a0681bda0cba0b4408a61f9115a4ee17e7e73945 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: Dot Slop
 date: 2025-09-18
 modified: 2025-09-23
-show: Build Weekly Roundup
-description: "2025 Week #38"
+description: "Build Weekly Roundup - 2025 Week #38"
 tags:
 - macro
 - bitcoin
similarity index 92%
rename from content/podcasts/2025-39.mdx
rename to content/podcasts/build-weekly-roundup-2025-39.mdx
index 8ae50806d964c76bfd69bf6ee0a666feb831e899..5b44fb5329f9f74cf53874711ba0af35a05d72a8 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: Government Shutdown
 date: 2025-09-26
 modified: 2025-10-02
-show: Build Weekly Roundup
-description: "2025 Week #39"
+description: "Build Weekly Roundup - 2025 Week #39"
 tags:
 - macro
 posse:
similarity index 92%
rename from content/podcasts/2025-40.mdx
rename to content/podcasts/build-weekly-roundup-2025-40.mdx
index b17136f1c43b8f756d3412c6c42fe77267b0f2a1..f37eca2eb19f3e463b3853df0d34a1bd631f3e47 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: Window of Heightened Risk
 date: 2025-10-02
 modified: 2025-10-02
-show: Build Weekly Roundup
-description: "2025 Week #40"
+description: "Build Weekly Roundup - 2025 Week #40"
 tags:
 - macro
 - bitcoin
similarity index 92%
rename from content/podcasts/2025-41.mdx
rename to content/podcasts/build-weekly-roundup-2025-41.mdx
index 2c6a7419a8f6f978758c72bebe0c1d6fa87ffd5b..27370ac29185d8a2e8886ee1eac0accc74967ce1 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: Equity Financing Bubble?
 date: 2025-10-09
 modified: 2025-10-09
-show: Build Weekly Roundup
-description: "2025 Week #41"
+description: "Build Weekly Roundup - 2025 Week #41"
 tags:
 - macro
 posse:
similarity index 92%
rename from content/podcasts/2025-42.mdx
rename to content/podcasts/build-weekly-roundup-2025-42.mdx
index a0225e1bcd247860dddabdce730ae4a875a8d480..b759f0fbf909800a0d935e6f27cb89c6d565f2f5 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: Debasement Awakening
 date: 2025-10-16
 modified: 2025-10-16
-show: Build Weekly Roundup
-description: "2025 Week #42"
+description: "Build Weekly Roundup - 2025 Week #42"
 tags:
 - macro
 posse:
similarity index 92%
rename from content/podcasts/2025-43.mdx
rename to content/podcasts/build-weekly-roundup-2025-43.mdx
index fee4e1f97707e87d22b70b748d3919d32f9b3961..d66942bf1e3c59591b8bc5d5d0acad4f4e01b80d 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: Control the World
 date: 2025-10-24
 modified: 2025-10-24
-show: Build Weekly Roundup
-description: "2025 Week #43"
+description: "Build Weekly Roundup - 2025 Week #43"
 tags:
 - macro
 - bitcoin
similarity index 92%
rename from content/podcasts/2025-44.mdx
rename to content/podcasts/build-weekly-roundup-2025-44.mdx
index f966ac30f548c39c80cd4c14b72fd9703ba95a9e..3cf7e4055665fc8e5841b76dd6c08b75e5ebd521 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: Caribbean Chaos
 date: 2025-10-30
 modified: 2025-10-30
-show: Build Weekly Roundup
-description: "2025 Week #44"
+description: "Build Weekly Roundup - 2025 Week #44"
 tags:
 - macro
 posse:
similarity index 92%
rename from content/podcasts/2025-45.mdx
rename to content/podcasts/build-weekly-roundup-2025-45.mdx
index 87fd12c73d0cacfefcdfc60726b6ec92949c8f8b..ca33ca395e36d1f2df0e852ad439fed6769fe29d 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: NYC Says Cuo"no"
 date: 2025-11-06
 modified: 2025-11-06
-show: Build Weekly Roundup
-description: "2025 Week #45"
+description: "Build Weekly Roundup - 2025 Week #45"
 tags:
 - macro
 - bitcoin
similarity index 92%
rename from content/podcasts/2025-46.mdx
rename to content/podcasts/build-weekly-roundup-2025-46.mdx
index 3789464296fc261b4b9b79b80231176c2c72e69e..dd4b69220db709336f6241f079b782f88e9e526f 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: Likely Suffer a Complete Loss
 date: 2025-11-13
 modified: 2025-11-13
-show: Build Weekly Roundup
-description: "2025 Week #46"
+description: "Build Weekly Roundup - 2025 Week #46"
 tags:
 - macro
 - bitcoin
similarity index 92%
rename from content/podcasts/2025-47.mdx
rename to content/podcasts/build-weekly-roundup-2025-47.mdx
index 32582ef822cb6677179a973ea9dd225695aac988..1b1ed97cbfcba009243ff29373d7dbdf83d89662 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: Reigning In the Offshore Dollar
 date: 2025-11-21
 modified: 2025-11-21
-show: Build Weekly Roundup
-description: "2025 Week #47"
+description: "Build Weekly Roundup - 2025 Week #47"
 tags:
 - macro
 - bitcoin
similarity index 92%
rename from content/podcasts/2025-48.mdx
rename to content/podcasts/build-weekly-roundup-2025-48.mdx
index f2f84fd4969f74d070e417342235cd9d497999a6..9e88c2025a46f908928d4b1e0ffc4ac82e4ca043 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: eSLR Tilts the Scale
 date: 2025-11-28
 modified: 2025-12-01
-show: Build Weekly Roundup
-description: "2025 Week #48"
+description: "Build Weekly Roundup - 2025 Week #48"
 tags:
 - ai
 - macro
similarity index 92%
rename from content/podcasts/2025-49.mdx
rename to content/podcasts/build-weekly-roundup-2025-49.mdx
index d3cb52d7f2e75e399f4d9df997dc807256885ada..919c8861c6ae2509140f5f64b8516987846ba7d4 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: ECB Urges Gold Rethink
 date: 2025-12-04
 modified: 2025-12-04
-show: Build Weekly Roundup
-description: "2025 Week #49"
+description: "Build Weekly Roundup - 2025 Week #49"
 tags:
 - ai
 - macro
similarity index 92%
rename from content/podcasts/2025-50.mdx
rename to content/podcasts/build-weekly-roundup-2025-50.mdx
index e0ddff59478d1c755fa9c1c9ddae756dd0f03740..c3f844159c85c443c172047b97f2acdaa09b43d4 100644 (file)
@@ -3,8 +3,7 @@ type: video
 title: Trade Route Control
 date: 2025-12-12
 modified: 2025-12-12
-show: Build Weekly Roundup
-description: "2025 Week #50"
+description: "Build Weekly Roundup - 2025 Week #50"
 tags:
 - macro
 posse:
index 632326ca9bf7ab3986e0e3fa17bba0291ef0fc67..4986a8f29838761927d83306818b91508e1fffaf 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: 28 Days Later
 date: 2025-06-06
 modified: 2025-12-07
index adbe3e47cdca893be0a8bf4495c54a461d591ec4..fe737e486a2a01069357bbafb279b01ee1cb7cb9 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: A Complete Unknown
 date: 2025-06-04
 modified: 2025-06-04
index 0c479637d23345404b25cabc7247a9333294b7cb..f8c465af55aa7d88d931c6520a9f25a532a61e72 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: Bugonia
 date: 2025-10-30
 modified: 2025-11-01
index adaf05709beece32b18fee611b6b7cb5640bee60..3b132d42e35b167d1bf27acf3b8e6d614df2c6d9 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: Burning
 date: 2025-02-28
 modified: 2025-03-02
index 89bd267682f999495c059e7baaec2ebdb6bc7e14..1426030d2fe3294ce67fabe0addcae95a868fb8d 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: Casino Royale
 date: 2025-12-14
 modified: 2025-12-16
index bbc926c478d692e4dfb853e79b7fd5bd3db474db..b748d922d0f7d10ad52f8e84e33123330198f784 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: Caught Stealing
 date: 2025-09-12
 modified: 2025-09-13
index bd4ee67dc0317d9555a03d786f9eab0f99f39678..b1e31edfeb0d0f8f4fd0f5d8f5909ee8ad81812a 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: Challengers
 date: 2024-12-24
 modified: 2024-12-26
index 656de8d5b9f817939c3f9e0d5d6d0081211bac38..535aa37c9a2ec035c93b9eec0dec8962239bb1b7 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: Conclave
 date: 2025-03-02
 modified: 2025-03-18
index 56b4c0e7ef5c44674d98cf702d4a53beaff095cc..cb9832bb3a5d27aedc78c83d3c31038486687808 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: Death Becomes Her
 date: 2025-10-02
 modified: 2025-10-07
index 970c35b25a4233f7c54a691f560d57e9fa298e97..4760cb546d073d8dfdbf0a111aa75316bcacd1ef 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: "Den of Thieves: Pantera"
 date: 2025-10-18
 modified: 2025-10-19
index 8efb01dd27c6986b5bddeba8d07916c19327dcc6..bb52953a0aba0335aaf2aea0e39f344aa189508d 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: "F1: The Movie"
 date: 2025-10-16
 modified: 2025-10-17
index f840145e633f26df84c4dab7568a80f934f5e361..3cc1136f5f95ea53aa57f337a35f40854b1e2dc7 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: Fallen Angels
 date: 2025-08-02
 modified: 2025-10-24
index e74e414aa5d70a525cd6df5c97e2c4eed14132d2..90dc4886a02da6603777d7b13c65eb3c7e9baa37 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: The Hunchback of Notre Dame
 date: 2025-03-04
 modified: 2025-03-22
index b405b20d472f7a0262d075048a2736dab97ad92f..4a31c5384fcbebfd2bdd58d7496684b25f74d011 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: It's What's Inside
 date: 2025-03-01
 modified: 2025-03-02
index dc616e4dd39e43970eabbe9dd3af0bc71ac9ae0b..1c982e156f7a022092e79496681560f56beccf4b 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: Jurassic Park
 date: 2025-09-10
 modified: 2025-09-13
index 1280894231aa27b9989b1d956d0924faae243607..451ac55ab61d7c70ff7b3672afcf151085d52675 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: Materialists
 date: 2025-08-14
 modified: 2025-08-15
index 14a62735cee17b2d49e083cff34df3ef1360f089..04ec81c3a6c26ef4f85789c0b588febe211aad3f 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: Mulholland Drive
 date: 2025-12-06
 modified: 2025-12-07
index 09030112e439cd7f678a451ecdc67ff964755333..5270bfed533154ee395fdf27c1c4025d9184da9e 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: Nosferatu
 date: 2025-09-09
 modified: 2025-09-13
index c42aa116c23f58f870d8f197eb9782aa23dc4bf3..6e3e803387d5e32cafe3ea4776c9ba6f17fc9777 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: One Battle After Another
 date: 2025-10-01
 modified: 2025-10-04
index 75048e3159c96c556ce34dfb22146a551df4625f..f6df0edcc53bc1aa9f3c7ca157ca3bd29af5de35 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: Perfect Days
 date: 2025-02-15
 modified: 2025-02-15
index d8a3f676f501ef758795907e4517eb6015f7d3d0..91fe0ab0025ead6cadfefd850d3371db14599134 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: Problemista
 date: 2025-11-04
 modified: 2025-11-06
index fcf368022a4477b8d5b57010bfd4934ed63e9467..11a93f0d7430e26732b54e00f13f696013ebb079 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: Sinners
 date: 2025-05-02
 modified: 2025-05-02
index ab41eeab01fdb30d47fdb764cabc4104b8acda87..fd89e2249565260ae621f002cc8d12360ea1da4e 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: "Star Wars: Episode III - Revenge of the Sith"
 date: 2025-09-05
 modified: 2025-09-07
index 54aa77814bec8805b60aa5194bbfdfa301248fe6..3d0f4885865e1014356b97d662fa0db8df0ac5ae 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: Subservience
 date: 2024-12-25
 modified: 2024-12-26
index 17b5b3e78cdf7cf7796c0a40b4fb82838a8f0b7f..bf567637730398c2201d68a1c440567a9a969ca2 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: Superman
 date: 2025-10-04
 modified: 2025-10-04
index 4fc5620ca58d38269c81d7a3bfc3c972fc8e1c8d..906239eb6652d3e208f915d694f044d48a0dfefe 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: The Apprentice
 date: 2025-09-06
 modified: 2025-09-07
index 1cf6c95c8a58339b8ff22cd535147b95b79f6457..98070f170aa376f8cda500281c22d0afd96a0c31 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: The Boy and the Heron
 date: 2024-12-21
 modified: 2024-12-23
index 1f77edc6769148defabcf0f291fd572fdf2edbc8..187e9577bf7cdd4fa7184ea7398290ebde111dc8 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: The Godfather
 date: 2025-11-16
 modified: 2025-11-19
index c1b347b0daf26d63f3aec32ef689bfa5344e4511..b3efe510ce55b319186ab5c50df41afdfa22a30e 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: "The Lord of the Rings: The Fellowship of the Ring"
 date: 2025-11-26
 modified: 2025-11-30
index 8b31aebf18ccf2effdccc3af4294dbe06692c125..f4def80bbeaafcb8c491b47a38a7715fb3b0ffea 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: Wake Up Dead Man
 date: 2025-12-15
 modified: 2025-12-16
index 8351233fe5734d087c44be4b476541b419a498eb..a53955c5427901243cc8f646fcfa773cdc91be60 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: Warfare
 date: 2025-04-11
 modified: 2025-04-11
index 7193df9a4d1e2ae39ddef9e2dd3cce58e5b1272a..925ce2ef916908be502a645cbe760f72836a9d64 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: "Wicked: For Good"
 date: 2025-11-25
 modified: 2025-11-25
index baec4b33c1195ae267a1c3b12df818d68e5efeb2..b0f65fdc89dcc39e750b7c9fa233b82597724c15 100644 (file)
@@ -1,5 +1,5 @@
 ---
-type: movie
+category: movie
 title: Wicked
 date: 2024-11-29
 modified: 2025-06-04
index d900be71508b75737e8fb2b34ed59fd456891f9e..0fe3ac8879b4d376c1335ecf7c9e01f6b4db790c 100644 (file)
     "@fontsource-variable/source-serif-4": "^5.2.9",
     "@iconify-json/mdi": "^1.2.3",
     "@vercel/og": "^0.8.5",
-    "astro": "5.16.3",
+    "astro": "5.16.5",
     "astro-icon": "^1.1.5",
-    "react": "^19.2.0",
-    "react-dom": "^19.2.0",
+    "react": "^19.2.3",
+    "react-dom": "^19.2.3",
     "recharts": "^3.5.1"
   },
   "devDependencies": {
-    "@types/bun": "^1.3.3",
+    "@types/bun": "^1.3.4",
     "@types/react": "^19.2.7",
     "@types/react-dom": "^19.2.3"
   }
index b9564218af271786abc961aaa6714385fc609426..9d7c471aed3553ab42e9173fa85652e4b3292c16 100644 (file)
@@ -1,5 +1,5 @@
 ---
-import { siteAuthor, socials } from '@utils/globals.ts';
+import { siteAuthor, socials } from '@utils/globals';
 import { Icon } from 'astro-icon/components';
 
 const currentYear = new Date().getFullYear();
index dc1efe0f9c731e5cf5f7abf295f558b7b6a409b9..746304ae0ba98448b64cfb75ecc57bd7241bd2db 100644 (file)
@@ -1,5 +1,5 @@
 ---
-import { siteAuthor } from '@utils/globals.ts';
+import { siteAuthor } from '@utils/globals';
 
 interface Props {
     publishedTime: string
index e469334e0820a5fbbc3aa5216bd2f1b12094aa87..9641518a91df08b36965204f448e326c94ad95a8 100644 (file)
@@ -1,6 +1,6 @@
 ---
 import { getImage } from 'astro:assets';
-import { siteAuthor, siteTitle, socials } from '@utils/globals.ts';
+import { siteAuthor, siteTitle, socials } from '@utils/globals';
 import FavIcon from '@assets/favicon.ico';
 
 interface Props {
index f2eacc50ac8de480b48c85e328466792dd5e6a1f..8e25977fde5388998ad8ff7ff705a80f87ad0a19 100644 (file)
@@ -1,10 +1,10 @@
 ---
-import { type InferEntrySchema } from 'astro:content';
-import formatDate from '@utils/formatDate.ts';
+import { type SiteEntrySchema } from '@utils/globals';
+import formatDate from '@utils/formatDate';
 import Rating from '@components/ui/rating.astro';
 
 interface Props {
-    entryData: InferEntrySchema<'articles' | 'podcasts' | 'reviews'>
+    entryData: SiteEntrySchema
 }
 
 const { entryData } = Astro.props;
@@ -14,7 +14,6 @@ const modifiedDate = entryData.modified ? formatDate(entryData.modified) : publi
 <details>
     <summary>Metadata</summary>
     <ul>
-        {'show' in entryData && entryData.show && <li>Show: {entryData.show}</li>}
         {entryData.description && <li>Description: {entryData.description}</li>}
         {'rating' in entryData && entryData.rating && <li>Rating: <Rating rating={entryData.rating} /></li>}
         <li>Published: <time datetime={publishedDate}>{publishedDate}</time></li>
index 51cf3467d20aef29a2df2618d6a95bdb57fd1177..9341206b8130077f6881b03c03364e609d6d3878 100644 (file)
@@ -1,5 +1,5 @@
 ---
-import { menuItems } from '@utils/globals.ts';
+import { menuItems } from '@utils/globals';
 ---
 <nav>
     <menu>
index 4d06976304be5bfefe3fa71cae8714f1eb694315..5d6a1011cd8417a47b5fe38d250b5950b3a8482c 100644 (file)
@@ -15,9 +15,9 @@ reviews.forEach(review => {
     const rating = review.data.rating;
     ratingCounts[rating]++;
 });
-const chartData = Object.keys(ratingCounts).map(rating => ({
+const chartData = Object.entries(ratingCounts).map(([rating, count]) => ({
     name: rating,
-    count: ratingCounts[parseInt(rating)]
+    count: count
 }));
 ---
 <Chart chartData={chartData} client:load />
\ No newline at end of file
index 729c924806b8500e39ad4ccabf706bcba4badbd1..d68a92f346454316c09b9980b9993d36989c6882 100644 (file)
@@ -1,5 +1,5 @@
 ---
-import generateStarRating from '@utils/generateStarRating.ts';
+import generateStarRating from '@utils/generateStarRating';
 
 interface Props {
     rating: number
@@ -8,6 +8,5 @@ interface Props {
 const { rating } = Astro.props;
 const starRating = generateStarRating(rating);
 ---
-<Fragment>
-    {starRating}
-</Fragment>
\ No newline at end of file
+
+{starRating}
\ No newline at end of file
index 636a835745cbb6e7fd87c5600e45eda9b98724c8..b18742dfbf7f60533a199c75b3e3d7c1fc4fb6d4 100644 (file)
@@ -7,7 +7,10 @@ interface Props {
 const { title, videoURL } = Astro.props;
 
 const url = new URL(videoURL);
-const videoID = url.searchParams.get("v");
+const videoID = url.searchParams.get('v');
+if (videoID == null) {
+    throw new Error('URL does not contain a v parameter.');
+}
 ---
 
 <iframe
index df666146fe4e3c747d70e4ef4a94b0a92835a08f..fed0b6e7ceeb628c1b0cd25fd1fe36b5463268c6 100644 (file)
@@ -1,56 +1,50 @@
-import { defineCollection, z } from 'astro:content';
+import { defineCollection } from 'astro:content';
 import { glob } from 'astro/loaders';
+import { z } from 'astro/zod';
+
+const baseSchema = z.object({
+    title: z.string(),
+    description: z.string().optional(),
+    date: z.coerce.date(),
+    modified: z.coerce.date().optional(),
+    tags: z.array(z.string()).optional(),
+    posse: z.record(
+        z.string(),
+        z.string().url()
+    ).optional()
+});
 
 const articles = defineCollection({
     loader: glob({ pattern: '**/*.{md,mdx}', base: 'content/articles' }),
-    schema: z.object({
-        title: z.string(),
-        description: z.string(),
-        date: z.coerce.date(),
-        modified: z.coerce.date().optional(),
-        tags: z.array(z.string()).optional(),
-        posse: z.record(z.string(), z.string().url()).optional()
-    })
+    schema: baseSchema
 });
 
-const PodcastType = z.enum([
-    "audio",
-    "video"
-])
-
 const podcasts = defineCollection({
     loader: glob({ pattern: '**/*.{md,mdx}', base: 'content/podcasts' }),
-    schema: z.object({
-        type: PodcastType,
-        title: z.string(),
-        show: z.string(),
-        description: z.string(),
-        date: z.coerce.date(),
-        modified: z.coerce.date().optional(),
-        tags: z.array(z.string()).optional(),
-        posse: z.record(z.string(), z.string().url()).optional()
+    schema: baseSchema.extend({
+        type: z.enum([
+            'audio',
+            'video'
+        ]),
+        enclosure: z.object({
+            url: z.string().url(),
+            length: z.number(),
+            type: z.string()
+        }).optional()
     })
 });
 
-const ReviewType = z.enum([
-    "game",
-    "movie",
-    "music",
-    "show"
-])
-
 const reviews = defineCollection({
     loader: glob({ pattern: '**/*.{md,mdx}', base: 'content/reviews' }),
-    schema: z.object({
-        type: ReviewType,
-        title: z.string(),
-        description: z.string().optional(),
+    schema: baseSchema.extend({
         rating: z.number().gt(0).lte(5).step(1),
-        date: z.coerce.date(),
-        modified: z.coerce.date().optional(),
-        tags: z.array(z.string()).optional(),
-        posse: z.record(z.string(), z.string().url()).optional()
+        category: z.enum([
+            'game',
+            'movie',
+            'music',
+            'show'
+        ])
     })
 });
 
-export const collections = { articles, podcasts, reviews };
\ No newline at end of file
+export const collections = { articles, podcasts, reviews }
\ No newline at end of file
index 0342e5909154d2c5da7284c091569d56296ea3b7..499cf1da120f4b5f51fae64f1988a231b3357195 100644 (file)
@@ -1,6 +1,6 @@
 ---
 import { type CollectionEntry, getCollection, render } from 'astro:content';
-import formatDate from '@utils/formatDate.ts';
+import formatDate from '@utils/formatDate';
 import Article from '@layouts/article.astro';
 import Metadata from '@components/metadata.astro';
 
index a9b24a87837619dc6ea65931a971110648fb07ea..dc95f8c3bbadd037e882aed4db8745072f49e227 100644 (file)
@@ -1,7 +1,7 @@
 import type { APIRoute } from 'astro';
 import { getCollection } from 'astro:content';
-import formatDate from '@utils/formatDate.ts';
-import generateOpenGraphImage from '@utils/generateOpenGraphImage.ts';
+import formatDate from '@utils/formatDate';
+import generateOpenGraphImage from '@utils/generateOpenGraphImage';
 
 export async function getStaticPaths() {
     const articles = await getCollection('articles');
index 9dac4e414513a0fb900a2e681d4c16ac3329f958..c17f2e31c9382699815a717af70b19feed530c67 100644 (file)
@@ -1,8 +1,7 @@
 ---
 import { getCollection } from 'astro:content';
-import formatDate from '@utils/formatDate.ts';
 import Base from '@layouts/base.astro';
-import sortByDate from '@utils/sortByDate.ts';
+import sortByDate from '@utils/sortByDate';
 import generateContentUrl from '@utils/generateContentUrl';
 
 const articles = await getCollection('articles');
@@ -13,12 +12,9 @@ const sortedArticles = sortByDate(articles);
     <h2>Articles</h2>
     <dl>
         {sortedArticles.map((article) => {
-            const date = formatDate(article.data.date);
             return (
                 <dt><a href={generateContentUrl(article)}>{article.data.title}</a></dt>
-                <dd>
-                    {article.data.description}
-                </dd>
+                <dd>{article.data.description}</dd>
             )
         })}
     </dl>
index 75b2378fd1a192ff21ef5c28d203a905e706df8f..ab30793aa24b9169999f9ca743a3e0dc4dea0b53 100644 (file)
@@ -1,12 +1,12 @@
 import { getContainerRenderer as getMDXRenderer } from '@astrojs/mdx';
 import rss, { type RSSFeedItem } from '@astrojs/rss';
-import { siteDescription, siteTitle } from '@utils/globals.ts';
+import { siteDescription, siteTitle } from '@utils/globals';
 import { type APIContext } from 'astro';
 import { getCollection, render } from 'astro:content';
 import { loadRenderers } from 'astro:container';
 import { experimental_AstroContainer as AstroContainer } from 'astro/container';
 import generateContentUrl from '@utils/generateContentUrl';
-import generateStarRating from '@utils/generateStarRating.ts';
+import generateStarRating from '@utils/generateStarRating';
 
 export async function GET(context: APIContext) {
   const articles = await getCollection('articles');
@@ -23,26 +23,26 @@ export async function GET(context: APIContext) {
     const { Content } = await render(item);
     const content = await container.renderToString(Content);
     const categories = (item.data.tags ?? []).concat(item.collection)
-    if ('type' in item.data) {
-      categories.push(item.data.type);
-    }
-    if ('show' in item.data) {
-      categories.push(item.data.show);
+    if ('category' in item.data) {
+      categories.push(item.data.category);
     }
 
-    var description: string;
+    let title: string;
+    let description: string;
     switch (item.collection) {
       case 'reviews':
         const starRating = generateStarRating(item.data.rating);
-        description = starRating
+        title = `${item.data.title} - ${starRating}`;
+        description = starRating;
         break;
       default:
-        description = item.data.description;
+        title = item.data.title;
+        description = item.data.description ?? '';
         break;
     }
 
     feedItems.push({
-      title: item.data.title,
+      title: title,
       link: link,
       pubDate: item.data.date,
       description: description,
index 1d0eb70637c7faf73265d7c925f5e16bcd013f6a..9ca5ee0079e2703b90d397dac22404d5caeee930 100644 (file)
@@ -1,6 +1,5 @@
 ---
 import Base from '@layouts/base.astro';
-import Callout from '@components/ui/callout.astro';
 
 const contributions = [
        {
@@ -28,10 +27,7 @@ const contributions = [
 
 <Base title="Home" description="Personal site of Cameron Otsuka, Head of Data and Analytics at Build Asset Management. Writing on Bitcoin, cryptography, privacy, security, and technology.">
        <section>
-               <p>I am <strong>Head of Data and Analytics</strong> at Build Asset Management, where I've helped launch a <a href="https://buildbitcoin.com/">private credit fund</a> investing into over-collateralized bitcoin-backed loans, a <a href="https://bfix.fund/">fixed income ETF</a> and related vehicles, and built the internal tech stack that glues everything together.</p>
-               <Callout level="info">
-                       Some topics currently holding my interest: data, analytics, economics, <a href="/bitcoin/">Bitcoin</a>, cryptography, privacy, security, urbanism, skiing &hellip;
-               </Callout>
+               <p>I am <strong>Head of Data and Analytics</strong> at Build Asset Management, where I've helped launch a <a href="https://buildbitcoin.com/">private credit fund</a> investing into over-collateralized <a href="/bitcoin/">bitcoin</a>-backed loans, a <a href="https://bfix.fund/">fixed income ETF</a> and related vehicles, and built the internal tech stack that glues everything together.</p>
        </section>
     <section>
                <h2>Contributions</h2>
similarity index 80%
rename from src/pages/podcasts/[show]-[id]/index.astro
rename to src/pages/podcasts/[id]/index.astro
index 1755bdafcd2b602bf876f9913cf2d14fa73d2e9a..791a8bfb7a7d273894ff1a13f856b309fdbbbec8 100644 (file)
@@ -2,7 +2,6 @@
 import { type CollectionEntry, getCollection, render } from 'astro:content';
 import Article from '@layouts/article.astro';
 import Metadata from '@components/metadata.astro';
-import createSlug from '@utils/createSlug.ts';
 
 interface Props {
     podcast: CollectionEntry<'podcasts'>
@@ -11,7 +10,7 @@ interface Props {
 export async function getStaticPaths() {
     const podcasts = await getCollection('podcasts');
     return podcasts.map(podcast => ({
-        params: { show: createSlug(podcast.data.show), id: podcast.id },
+        params: { id: podcast.id },
         props: { podcast },
     }));
 }
@@ -21,7 +20,7 @@ const { Content } = await render(podcast);
 ---
 <Article
      title={podcast.data.title}
-     description={`${podcast.data.show} - ${podcast.data.description}`}
+     description={podcast.data.description}
      publishedTime={podcast.data.date.toISOString()}
      modifiedTime={podcast.data.modified?.toISOString() ?? podcast.data.date.toISOString()}
      tags={podcast.data.tags}
similarity index 69%
rename from src/pages/podcasts/[show]-[id]/opengraph.png.ts
rename to src/pages/podcasts/[id]/opengraph.png.ts
index 114ac82ac227223a09ce5c87be093a7b9bd165a2..d77d523ccf08a7033916f3a2b93b75e967b1c161 100644 (file)
@@ -1,12 +1,11 @@
 import type { APIRoute } from 'astro';
 import { getCollection } from 'astro:content';
-import createSlug from '@utils/createSlug.ts';
-import generateOpenGraphImage from '@utils/generateOpenGraphImage.ts';
+import generateOpenGraphImage from '@utils/generateOpenGraphImage';
 
 export async function getStaticPaths() {
     const podcasts = await getCollection('podcasts');
     return podcasts.map(podcast => ({
-        params: { show: createSlug(podcast.data.show), id: podcast.id },
+        params: { id: podcast.id },
         props: { podcast },
     }));
 };
@@ -14,6 +13,6 @@ export async function getStaticPaths() {
 export const GET: APIRoute = async ({ props }) => {
     return generateOpenGraphImage(
         props.podcast.data.title,
-        `${props.podcast.data.show} - ${props.podcast.data.description}`
+        props.podcast.data.description
     )
 };
\ No newline at end of file
index bfbb1fbc41f9431da00c52989fd6e794ff187d25..f77a9b564af2bb0d96c0d85ec7aac9aeb7d584f1 100644 (file)
@@ -1,8 +1,7 @@
 ---
 import { getCollection } from 'astro:content';
-import formatDate from '@utils/formatDate.ts';
 import Base from '@layouts/base.astro';
-import sortByDate from '@utils/sortByDate.ts';
+import sortByDate from '@utils/sortByDate';
 import generateContentUrl from '@utils/generateContentUrl';
 
 const podcasts = await getCollection('podcasts');
@@ -11,36 +10,12 @@ const sortedPodcasts = sortByDate(podcasts);
 
 <Base title="Podcasts" description="Weekly podcast episodes covering capital markets, Bitcoin, economic policy, and geopolitical events. Join Cameron Otsuka in his podcast appearances.">
     <h2>Podcasts</h2>
-    <table>
-        <thead>
-            <tr>
-                <th>Show</th>
-                <th>Title</th>
-                <th>Date</th>
-            </tr>
-        </thead>
-        <tbody>
-            {sortedPodcasts.map((podcast) => (
-                <tr>
-                    <td>{podcast.data.show}</td>
-                    <td>
-                        <dl>
-                            <dt><a href={generateContentUrl(podcast)}>{podcast.data.title}</a></dt>
-                            <dd>{podcast.data.description}</dd>
-                        </dl>
-                    </td>
-                    <td>{formatDate(podcast.data.date)}</td>
-                </tr>
-            ))}
-        </tbody>
-    </table>
-</Base>
-
-<style>
-    table {
-        width: 100%;
-    }
-    td:nth-child(2) {
-        text-align: left;
-    }
-</style>
\ No newline at end of file
+    <dl>
+        {sortedPodcasts.map((podcast) => {
+            return (
+                <dt><a href={generateContentUrl(podcast)}>{podcast.data.title}</a></dt>
+                <dd>{podcast.data.description}</dd>
+            )
+        })}
+    </dl>
+</Base>
\ No newline at end of file
similarity index 92%
rename from src/pages/reviews/[type]/[id]/index.astro
rename to src/pages/reviews/[category]/[id]/index.astro
index 3ae520471ee2c54f8191df4757990039563b6723..dd1a9dd37c367f1486df2032e45c51e9d7dbc25d 100644 (file)
@@ -10,7 +10,7 @@ interface Props {
 export async function getStaticPaths() {
     const reviews = await getCollection('reviews');
     return reviews.map(review => ({
-        params: { type: review.data.type, id: review.id },
+        params: { category: review.data.category, id: review.id },
         props: { review },
     }));
 }
similarity index 79%
rename from src/pages/reviews/[type]/[id]/opengraph.png.ts
rename to src/pages/reviews/[category]/[id]/opengraph.png.ts
index 960be4627737e66fe6a8528f865d4af067882dd0..d8b5c54d739d71dabb421d31a60984e4b622fef8 100644 (file)
@@ -1,12 +1,12 @@
 import type { APIRoute } from 'astro';
 import { getCollection } from 'astro:content';
-import generateOpenGraphImage from '@utils/generateOpenGraphImage.ts';
-import generateStarRating from '@utils/generateStarRating.ts';
+import generateOpenGraphImage from '@utils/generateOpenGraphImage';
+import generateStarRating from '@utils/generateStarRating';
 
 export async function getStaticPaths() {
     const reviews = await getCollection('reviews');
     return reviews.map(review => ({
-        params: { type: review.data.type, id: review.id },
+        params: { category: review.data.category, id: review.id },
         props: { review },
     }));
 };
index 2c98f2035de38e13816a4def6eb0e01efc6cd5f8..8fdf09af0362a1d54b5477822b23eee374cd6406 100644 (file)
@@ -3,7 +3,7 @@ import { getCollection } from 'astro:content';
 import Base from '@layouts/base.astro';
 import RatingDistribution from '@components/ratingdistribution/component.astro';
 import Rating from '@components/ui/rating.astro';
-import sortByDate from '@utils/sortByDate.ts';
+import sortByDate from '@utils/sortByDate';
 import generateContentUrl from '@utils/generateContentUrl';
 
 const reviews = await getCollection('reviews');
@@ -20,7 +20,7 @@ const sortedReviews = sortByDate(reviews);
         <table>
             <thead>
                 <tr>
-                    <th>Type</th>
+                    <th>Category</th>
                     <th>Title</th>
                     <th>Rating</th>
                 </tr>
@@ -28,7 +28,7 @@ const sortedReviews = sortByDate(reviews);
             <tbody>
                 {sortedReviews.map((review) => (
                     <tr>
-                        <td>{review.data.type}</td>
+                        <td>{review.data.category}</td>
                         <td><a href={generateContentUrl(review)}>{review.data.title}</a></td>
                         <td><Rating rating={review.data.rating} /></td>
                     </tr>
index 8c3b8083f057a8883bc78eff100ac5334dbfd0be..5fb3dc935c65679f023f5089c23ce2910dff35ac 100644 (file)
@@ -1,4 +1,4 @@
-export default function (text: string): string {
+export default function createSlug(text: string): string {
     return (
         text
             .trim()
index 5dbb874474929e9a599335536cd0792f250fe3d2..1e93db7fe67c6a8c4c4c880664f65bc7a2b5f701 100644 (file)
@@ -1,4 +1,4 @@
-export default function (date: Date): string {
+export default function formatDate(date: Date): string {
   const year = date.getUTCFullYear();
   const month = String(date.getUTCMonth() + 1).padStart(2, '0');
   const day = String(date.getUTCDate()).padStart(2, '0');
index 45715e00bad3ba34a80ef9a8d021342d6a0b0095..9e72f40eca54ba333ff9bab40d4ef535fe03d65c 100644 (file)
@@ -1,14 +1,13 @@
-import formatDate from '@utils/formatDate.ts';
-import createSlug from '@utils/createSlug.ts';
-import { type CollectionEntry } from 'astro:content';
+import formatDate from '@utils/formatDate';
+import { type SiteCollectionEntry } from '@utils/globals';
 
-export default function (item: CollectionEntry<'articles' | 'podcasts' | 'reviews'>): string {
+export default function generateContentUrl(item: SiteCollectionEntry): string {
     switch (item.collection) {
         case 'articles':
             return `/articles/${formatDate(item.data.date)}-${item.id}/`
         case 'podcasts':
-            return `/podcasts/${createSlug(item.data.show)}-${item.id}/`
+            return `/podcasts/${item.id}/`
         case 'reviews':
-            return `/reviews/${item.data.type}/${item.id}/`
+            return `/reviews/${item.data.category}/${item.id}/`
     }
 }
\ No newline at end of file
index 8c89b3e5b193f8e2da56f860c816a1ab8784c67a..47ae1f46c7e1f2a344b86e8078652a23b8076b3e 100644 (file)
@@ -1,8 +1,8 @@
 import { ImageResponse } from '@vercel/og';
-import { siteAuthor } from '@utils/globals.ts';
+import { siteAuthor } from '@utils/globals';
 
 async function loadFont(fontName: string) {
-    var url: string
+    let url: string
     switch (fontName) {
         case 'Public Sans Variable':
             url = `https://cdn.jsdelivr.net/fontsource/fonts/public-sans@latest/latin-400-normal.ttf`;
@@ -15,13 +15,13 @@ async function loadFont(fontName: string) {
     }
     
     const font = await fetch(url);
-    if (font) {
+    if (font.ok) {
         return await font.arrayBuffer();
     }
     throw new Error('failed to load font data');
 }
 
-export default async function (title: string, description: string) {
+export default async function generateOpenGraphImage(title: string, description: string) {
     const element = {
         type: 'div',
         props: {
index 0c3688b977688bac92f5d72868fdd635d3a43397..1ea122d54f81a132dd4906117ee0518bdbecf92d 100644 (file)
@@ -1,5 +1,9 @@
-export default function (rating: number): string {
-    const filledStars = '★'.repeat(rating);
-    const unfilledStars = '☆'.repeat(5 - rating);
-    return filledStars + unfilledStars;
+export default function generateStarRating(rating: number): string {
+    if (Number.isInteger(rating) && rating >= 1 && rating <= 5) {
+        const filledStars = '★'.repeat(rating);
+        const unfilledStars = '☆'.repeat(5 - rating);
+        return filledStars + unfilledStars;
+    } else {
+        throw new Error('rating is not an integer between 1 and 5');
+    }
 }
\ No newline at end of file
index 32363676e38add9be59e6d76304860d0da16e005..b9698f4e5fd522af48efcc7afd65f825cfbb725d 100644 (file)
@@ -1,9 +1,13 @@
+import type { CollectionEntry, InferEntrySchema } from 'astro:content';
+
 export const siteTitle = "Cameron Otsuka";
 export const siteDescription = "Cameron Otsuka's personal site featuring Bitcoin analysis, capital market insights, and thoughtful commentary on technology, privacy, and culture."
 export const siteAuthor = {
   "name": "Cameron Otsuka",
   "email": "cameron@otsuka.haus"
 }
+export type SiteCollectionEntry = CollectionEntry<'articles' | 'podcasts' | 'reviews'>;
+export type SiteEntrySchema = InferEntrySchema<'articles' | 'podcasts' | 'reviews'>;
 
 export const menuItems: {title: string, url: string}[] = [
   { "title": "Articles", "url": "/articles" },
index efe0c0c24aefa41390d524aae66d5048b769be62..82b865f72c49a7dddb4f39c53c8f0f311d53c5ae 100644 (file)
@@ -1,5 +1,5 @@
-import { type CollectionEntry } from 'astro:content';
+import { type SiteCollectionEntry } from '@utils/globals';
 
-export default function (items: CollectionEntry<'articles' | 'podcasts' | 'reviews'>[]): CollectionEntry<'articles' | 'podcasts' | 'reviews'>[] {
+export default function sortByDate(items: SiteCollectionEntry[]): SiteCollectionEntry[] {
     return items.sort((a, b) => b.data.date.getTime() - a.data.date.getTime());
 }
\ No newline at end of file