just a website
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor: remove worker script and related tests; update dependencies and documentation

+97 -141
-2
.github/workflows/deploy.yml
··· 26 26 key: ${{ runner.os }}-deps-${{ hashFiles('**/package-lock.json', '**/*.qmd') }} 27 27 restore-keys: | 28 28 ${{ runner.os }}-deps- 29 - - name: Run worker tests 30 - run: npm test 31 29 - name: Set up R 32 30 uses: r-lib/actions/setup-r@v2 33 31 with:
+6 -12
AGENTS.md
··· 16 16 |---|---| 17 17 | Site framework | Quarto | 18 18 | Styling | Custom SCSS (`assets/custom.scss`), no Quarto theme (`theme: none`) | 19 - | Hosting | Cloudflare Workers (static assets via Wrangler) | 19 + | Hosting | Cloudflare Workers static assets (deployed via Wrangler, no Worker script) | 20 20 | CI/CD | GitHub Actions (`.github/workflows/deploy.yml`) | 21 21 | R environment | renv | 22 22 | Analytics | Simple Analytics | ··· 36 36 analytics.html # Simple Analytics script injection 37 37 a11y.html # Accessibility enhancements (ARIA landmarks, roles) 38 38 skip-link.html # Skip-to-content link injected into every page 39 - src/ 40 - index.js # Cloudflare Worker entry point — lowercases URL paths before serving assets 41 - tests/ 42 - index.test.js # Worker unit tests (Node.js built-in runner); run with `npm test` 43 39 posts/ # Blog posts, each in its own subdirectory with index.qmd 44 40 _metadata.yml # Shared frontmatter defaults for all posts (freeze: auto) 45 41 404.qmd # Custom 404 page ··· 103 99 The site is **never built locally** — CI handles it. The full pipeline runs on every push to `main`: 104 100 105 101 1. Restore cached `_freeze/` and `node_modules/` (keyed by OS + hash of `package-lock.json` and all `.qmd` files) 106 - 2. Run `npm test` — Node.js built-in test runner, tests in `tests/index.test.js` 107 - 3. Set up R + renv (restores packages from `renv.lock`) 108 - 4. Run `quarto render` → outputs to `_site/` 109 - 5. Run `wrangler deploy` → uploads `_site/` to Cloudflare Workers 102 + 2. Set up R + renv (restores packages from `renv.lock`) 103 + 3. Run `quarto render` → outputs to `_site/` 104 + 4. Run `wrangler deploy` → uploads `_site/` to Cloudflare Workers 110 105 111 106 **Runner**: `blacksmith-4vcpu-ubuntu-2404-arm` (4-core ARM Ubuntu 24.04) 112 107 ··· 124 119 - Static assets served from `_site/` 125 120 - `not_found_handling: "404-page"` — unmatched routes serve the rendered `404.html` 126 121 - `html_handling: "auto-trailing-slash"` — URL normalisation (nested under `assets`) 127 - - Custom domain: `rorylawless.com` 128 - - `run_worker_first: true` — `src/index.js` intercepts every request before the assets binding responds; it lowercases URL paths and issues a 301 redirect, then falls through to `env.ASSETS.fetch()` 122 + - Custom domains: `rorylawless.com` and `www.rorylawless.com` (both route to the same Worker) 129 123 - Observability: full logs and traces enabled at 100% head sampling rate with persistence (viewable in the Cloudflare dashboard) 130 124 131 - URL redirects live in `_redirects` (Cloudflare syntax). Response headers live in `_headers` — currently used to set CORS headers and `Content-Type` for the PGP key endpoint at `/.well-known/openpgpkey/`. 125 + There is no Worker script — the deployment is static assets only. URL redirects live in `_redirects` (Cloudflare syntax). Response headers live in `_headers` — currently used to set CORS headers and `Content-Type` for the PGP key endpoint at `/.well-known/openpgpkey/`. A Cloudflare Redirect Rule (configured in the dashboard, not the repo) 301s `www.rorylawless.com` to the apex. 132 126 133 127 --- 134 128
+3 -1
_redirects
··· 1 1 /posts/r-duckdb-and-me /posts/the-basics-of-duckdb-in-r 2 - /posts/r-duckdb-and-me.html /posts/the-basics-of-duckdb-in-r 2 + /posts/r-duckdb-and-me.html /posts/the-basics-of-duckdb-in-r 3 + /posts/using-1password-secret-references-in-R /posts/using-1password-secret-references-in-r 4 + /posts/using-1password-secret-references-in-R.html /posts/using-1password-secret-references-in-r
+82 -34
package-lock.json
··· 5 5 "packages": { 6 6 "": { 7 7 "devDependencies": { 8 - "wrangler": "^4.83.0" 8 + "wrangler": "^4" 9 9 } 10 10 }, 11 11 "node_modules/@cloudflare/kv-asset-handler": { ··· 35 35 } 36 36 }, 37 37 "node_modules/@cloudflare/workerd-darwin-64": { 38 - "version": "1.20260415.1", 39 - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260415.1.tgz", 40 - "integrity": "sha512-dsxaKsQm3LnPGNPEdsRv09QN3Y4DqCw7kX5j6noKqbAtro2jTr95sVlYM1jUxZ5FkOl1f7SXgaKKB9t5H5Nkbg==", 38 + "version": "1.20260421.1", 39 + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260421.1.tgz", 40 + "integrity": "sha512-DLU5ZTZ1VHeZZnj0PuVJEMHKGisfLe2XShyImP5P/PPj/m/t7CLEJmPiI7FMxvT7ynArkckJl7m+Z5x7u4Kkdw==", 41 41 "cpu": [ 42 42 "x64" 43 43 ], ··· 52 52 } 53 53 }, 54 54 "node_modules/@cloudflare/workerd-darwin-arm64": { 55 - "version": "1.20260415.1", 56 - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260415.1.tgz", 57 - "integrity": "sha512-+JgSgVA49KyKteHRA1SnonE4Zn5Ei5zdAp5FQMxFmXI8qulZw4Hl7safXxRyK4i9sTO8gl7TFOKO5Q64VPvSDQ==", 55 + "version": "1.20260421.1", 56 + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260421.1.tgz", 57 + "integrity": "sha512-Trotq3xRAkIcpC505WoxM8+kIH4JIvOJCNuRatyHcz9uF5S+ukgiVUFUlM+GIjw1uCM/Bda2St+vSniX1RZdpw==", 58 58 "cpu": [ 59 59 "arm64" 60 60 ], ··· 69 69 } 70 70 }, 71 71 "node_modules/@cloudflare/workerd-linux-64": { 72 - "version": "1.20260415.1", 73 - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260415.1.tgz", 74 - "integrity": "sha512-tU+9pwsqCy8afOVlGtiWrWQc/fedQK4SRm4KPIAt+zOiQWDxWASm6YGBUJis5c648WN80yz47qnmdDi8DQNOcA==", 72 + "version": "1.20260421.1", 73 + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260421.1.tgz", 74 + "integrity": "sha512-938QjUv0z+QqK6BAvgwX/lCIZ2b224ZXoXtGTbhyNVMhB+mt4Dj24cj9qca4ekNXjVM7uTKp1yOHZO97fVSacw==", 75 75 "cpu": [ 76 76 "x64" 77 77 ], ··· 86 86 } 87 87 }, 88 88 "node_modules/@cloudflare/workerd-linux-arm64": { 89 - "version": "1.20260415.1", 90 - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260415.1.tgz", 91 - "integrity": "sha512-bR9uITnV19r5NQ14xnypi2xHXu2iQvfYV8cVgx0JouFUmWwTEEAwFVojDdssGq93VHX9hr/pi2IRUZeegbYBog==", 89 + "version": "1.20260421.1", 90 + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260421.1.tgz", 91 + "integrity": "sha512-YI4+mLfwnJcKJ+iPyxzx+tp2Jy4o29BxBPSQGZxl/AZyvZ9eTKsmNZmtjEiT4i3O/M0tdO/B/d9ESDHbRCs2rQ==", 92 92 "cpu": [ 93 93 "arm64" 94 94 ], ··· 103 103 } 104 104 }, 105 105 "node_modules/@cloudflare/workerd-windows-64": { 106 - "version": "1.20260415.1", 107 - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260415.1.tgz", 108 - "integrity": "sha512-4NuMLlerI0Ijua3Ir8HXQ+qyNvCUDEG5gDco5Om+sAiK6rnWiz+aGoSlbB8W16yW9QAgzCstbmXLiVknUBflfQ==", 106 + "version": "1.20260421.1", 107 + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260421.1.tgz", 108 + "integrity": "sha512-q1SFgwlNH9lFmw74vh7EJbJtduo92Nx51mNOfd3/u6pux6AldcwRviYzKEEv3FEbtv6OBB7J8D5f8vtZj7Z6Sg==", 109 109 "cpu": [ 110 110 "x64" 111 111 ], ··· 683 683 "arm" 684 684 ], 685 685 "dev": true, 686 + "libc": [ 687 + "glibc" 688 + ], 686 689 "license": "LGPL-3.0-or-later", 687 690 "optional": true, 688 691 "os": [ ··· 700 703 "arm64" 701 704 ], 702 705 "dev": true, 706 + "libc": [ 707 + "glibc" 708 + ], 703 709 "license": "LGPL-3.0-or-later", 704 710 "optional": true, 705 711 "os": [ ··· 717 723 "ppc64" 718 724 ], 719 725 "dev": true, 726 + "libc": [ 727 + "glibc" 728 + ], 720 729 "license": "LGPL-3.0-or-later", 721 730 "optional": true, 722 731 "os": [ ··· 734 743 "riscv64" 735 744 ], 736 745 "dev": true, 746 + "libc": [ 747 + "glibc" 748 + ], 737 749 "license": "LGPL-3.0-or-later", 738 750 "optional": true, 739 751 "os": [ ··· 751 763 "s390x" 752 764 ], 753 765 "dev": true, 766 + "libc": [ 767 + "glibc" 768 + ], 754 769 "license": "LGPL-3.0-or-later", 755 770 "optional": true, 756 771 "os": [ ··· 768 783 "x64" 769 784 ], 770 785 "dev": true, 786 + "libc": [ 787 + "glibc" 788 + ], 771 789 "license": "LGPL-3.0-or-later", 772 790 "optional": true, 773 791 "os": [ ··· 785 803 "arm64" 786 804 ], 787 805 "dev": true, 806 + "libc": [ 807 + "musl" 808 + ], 788 809 "license": "LGPL-3.0-or-later", 789 810 "optional": true, 790 811 "os": [ ··· 802 823 "x64" 803 824 ], 804 825 "dev": true, 826 + "libc": [ 827 + "musl" 828 + ], 805 829 "license": "LGPL-3.0-or-later", 806 830 "optional": true, 807 831 "os": [ ··· 819 843 "arm" 820 844 ], 821 845 "dev": true, 846 + "libc": [ 847 + "glibc" 848 + ], 822 849 "license": "Apache-2.0", 823 850 "optional": true, 824 851 "os": [ ··· 842 869 "arm64" 843 870 ], 844 871 "dev": true, 872 + "libc": [ 873 + "glibc" 874 + ], 845 875 "license": "Apache-2.0", 846 876 "optional": true, 847 877 "os": [ ··· 865 895 "ppc64" 866 896 ], 867 897 "dev": true, 898 + "libc": [ 899 + "glibc" 900 + ], 868 901 "license": "Apache-2.0", 869 902 "optional": true, 870 903 "os": [ ··· 888 921 "riscv64" 889 922 ], 890 923 "dev": true, 924 + "libc": [ 925 + "glibc" 926 + ], 891 927 "license": "Apache-2.0", 892 928 "optional": true, 893 929 "os": [ ··· 911 947 "s390x" 912 948 ], 913 949 "dev": true, 950 + "libc": [ 951 + "glibc" 952 + ], 914 953 "license": "Apache-2.0", 915 954 "optional": true, 916 955 "os": [ ··· 934 973 "x64" 935 974 ], 936 975 "dev": true, 976 + "libc": [ 977 + "glibc" 978 + ], 937 979 "license": "Apache-2.0", 938 980 "optional": true, 939 981 "os": [ ··· 957 999 "arm64" 958 1000 ], 959 1001 "dev": true, 1002 + "libc": [ 1003 + "musl" 1004 + ], 960 1005 "license": "Apache-2.0", 961 1006 "optional": true, 962 1007 "os": [ ··· 980 1025 "x64" 981 1026 ], 982 1027 "dev": true, 1028 + "libc": [ 1029 + "musl" 1030 + ], 983 1031 "license": "Apache-2.0", 984 1032 "optional": true, 985 1033 "os": [ ··· 1261 1309 } 1262 1310 }, 1263 1311 "node_modules/miniflare": { 1264 - "version": "4.20260415.0", 1265 - "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20260415.0.tgz", 1266 - "integrity": "sha512-JoExRWN4YBI2luA5BoSMFEgi8rQWXUGzo3mtE+58VXCLV3jj/Xnk5Yeqs/IXWz8Es5GJIaq6BtsixDvAxXSIng==", 1312 + "version": "4.20260421.0", 1313 + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20260421.0.tgz", 1314 + "integrity": "sha512-7ZkNQ7brgQ2hh5ha9iQCDUjxBkLvuiG2VdDns9esRL8O8lXg+MoP6E0dO1rtp+ZY2I+vV1tPWr6td5IojkewLw==", 1267 1315 "dev": true, 1268 1316 "license": "MIT", 1269 1317 "dependencies": { 1270 1318 "@cspotcode/source-map-support": "0.8.1", 1271 1319 "sharp": "^0.34.5", 1272 1320 "undici": "7.24.8", 1273 - "workerd": "1.20260415.1", 1321 + "workerd": "1.20260421.1", 1274 1322 "ws": "8.18.0", 1275 1323 "youch": "4.1.0-beta.10" 1276 1324 }, ··· 1395 1443 } 1396 1444 }, 1397 1445 "node_modules/workerd": { 1398 - "version": "1.20260415.1", 1399 - "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20260415.1.tgz", 1400 - "integrity": "sha512-phyPjRnx+mQDfkhN9ENPioL1L0SdhYs4S0YmJK/xF9Oga+ykNfdSy1MHnsOj8yqnOV96zcVQMx32dJ0r3pq0jQ==", 1446 + "version": "1.20260421.1", 1447 + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20260421.1.tgz", 1448 + "integrity": "sha512-zTYD+xFR4d7TUCxsyl7FTPth9a8CDgk8pM7xUWbJxo0SGUx+2e5C7Q5LrramBZwmuAErtzXmOjlQ15PtkPAhZA==", 1401 1449 "dev": true, 1402 1450 "hasInstallScript": true, 1403 1451 "license": "Apache-2.0", ··· 1408 1456 "node": ">=16" 1409 1457 }, 1410 1458 "optionalDependencies": { 1411 - "@cloudflare/workerd-darwin-64": "1.20260415.1", 1412 - "@cloudflare/workerd-darwin-arm64": "1.20260415.1", 1413 - "@cloudflare/workerd-linux-64": "1.20260415.1", 1414 - "@cloudflare/workerd-linux-arm64": "1.20260415.1", 1415 - "@cloudflare/workerd-windows-64": "1.20260415.1" 1459 + "@cloudflare/workerd-darwin-64": "1.20260421.1", 1460 + "@cloudflare/workerd-darwin-arm64": "1.20260421.1", 1461 + "@cloudflare/workerd-linux-64": "1.20260421.1", 1462 + "@cloudflare/workerd-linux-arm64": "1.20260421.1", 1463 + "@cloudflare/workerd-windows-64": "1.20260421.1" 1416 1464 } 1417 1465 }, 1418 1466 "node_modules/wrangler": { 1419 - "version": "4.83.0", 1420 - "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.83.0.tgz", 1421 - "integrity": "sha512-gw5g3LCiuAqVWxaoKY6+quE0HzAUEFb/FV3oAlNkE1ttd4XP3FiV91XDkkzUCcdqxS4WjhQvPhIDBNdhEi8P0A==", 1467 + "version": "4.84.1", 1468 + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.84.1.tgz", 1469 + "integrity": "sha512-Xe1S/Bik7pNdtdJ+asHsEZC2dX9k3WxYn2BbxFtOrrLVxN/LKi750zsrjX41jSAk00M/O1l7jzyQV4sQqw8ftg==", 1422 1470 "dev": true, 1423 1471 "license": "MIT OR Apache-2.0", 1424 1472 "dependencies": { ··· 1426 1474 "@cloudflare/unenv-preset": "2.16.0", 1427 1475 "blake3-wasm": "2.1.5", 1428 1476 "esbuild": "0.27.3", 1429 - "miniflare": "4.20260415.0", 1477 + "miniflare": "4.20260421.0", 1430 1478 "path-to-regexp": "6.3.0", 1431 1479 "unenv": "2.0.0-rc.24", 1432 - "workerd": "1.20260415.1" 1480 + "workerd": "1.20260421.1" 1433 1481 }, 1434 1482 "bin": { 1435 1483 "wrangler": "bin/wrangler.js", ··· 1442 1490 "fsevents": "~2.3.2" 1443 1491 }, 1444 1492 "peerDependencies": { 1445 - "@cloudflare/workers-types": "^4.20260415.1" 1493 + "@cloudflare/workers-types": "^4.20260421.1" 1446 1494 }, 1447 1495 "peerDependenciesMeta": { 1448 1496 "@cloudflare/workers-types": {
+1 -4
package.json
··· 1 1 { 2 2 "type": "module", 3 - "scripts": { 4 - "test": "node --test" 5 - }, 6 3 "devDependencies": { 7 - "wrangler": "^4.83.0" 4 + "wrangler": "^4" 8 5 } 9 6 }
+3 -3
renv.lock
··· 317 317 }, 318 318 "fs": { 319 319 "Package": "fs", 320 - "Version": "2.0.1", 320 + "Version": "2.1.0", 321 321 "Source": "Repository", 322 322 "Title": "Cross-Platform File System Operations Based on 'libuv'", 323 323 "Authors@R": "c( person(\"Jim\", \"Hester\", role = \"aut\"), person(\"Hadley\", \"Wickham\", role = \"aut\"), person(\"Gábor\", \"Csárdi\", role = \"aut\"), person(\"Jeroen\", \"Ooms\", , \"jeroenooms@gmail.com\", role = \"cre\"), person(\"libuv project contributors\", role = \"cph\", comment = \"libuv library\"), person(\"Joyent, Inc. and other Node contributors\", role = \"cph\", comment = \"libuv library\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\"), comment = c(ROR = \"03wc8by49\")) )", ··· 671 671 }, 672 672 "renv": { 673 673 "Package": "renv", 674 - "Version": "1.2.1", 674 + "Version": "1.2.2", 675 675 "Source": "Repository", 676 676 "Type": "Package", 677 677 "Title": "Project Environments", ··· 722 722 "NeedsCompilation": "no", 723 723 "Author": "Kevin Ushey [aut, cre] (ORCID: <https://orcid.org/0000-0003-2880-7407>), Hadley Wickham [aut] (ORCID: <https://orcid.org/0000-0003-4757-117X>), Posit Software, PBC [cph, fnd]", 724 724 "Maintainer": "Kevin Ushey <kevin@rstudio.com>", 725 - "Repository": "CRAN" 725 + "Repository": "https://packagemanager.posit.co/cran/latest" 726 726 }, 727 727 "rlang": { 728 728 "Package": "rlang",
+2 -2
renv/activate.R
··· 2 2 local({ 3 3 4 4 # the requested version of renv 5 - version <- "1.2.1" 6 - attr(version, "md5") <- "51fff37c14949274ac148a9a087ab6bd" 5 + version <- "1.2.2" 6 + attr(version, "md5") <- "bb69b6403b1bad0442657e9e8e57cc83" 7 7 attr(version, "sha") <- NULL 8 8 9 9 # the project directory
-17
src/index.js
··· 1 - const PATH_REGEX = /%[0-9A-Fa-f]{2}|[A-Z]/g; 2 - 3 - export default { 4 - async fetch(request, env) { 5 - const url = new URL(request.url); 6 - const lower = url.pathname.replace(PATH_REGEX, (m) => 7 - m.length === 1 ? m.toLowerCase() : m, 8 - ); 9 - 10 - if (url.pathname !== lower) { 11 - url.pathname = lower; 12 - return Response.redirect(url.toString(), 301); 13 - } 14 - 15 - return env.ASSETS.fetch(request); 16 - }, 17 - };
-64
tests/index.test.js
··· 1 - import test from 'node:test'; 2 - import assert from 'node:assert'; 3 - import worker from '../src/index.js'; 4 - 5 - test('redirects uppercase paths to lowercase', async () => { 6 - const request = new Request('https://example.com/UPPERCASE'); 7 - const env = { 8 - ASSETS: { 9 - fetch: () => new Response('ok') 10 - } 11 - }; 12 - 13 - const response = await worker.fetch(request, env); 14 - 15 - assert.strictEqual(response.status, 301); 16 - assert.strictEqual(response.headers.get('Location'), 'https://example.com/uppercase'); 17 - }); 18 - 19 - test('does not redirect lowercase paths', async () => { 20 - const request = new Request('https://example.com/lowercase'); 21 - const env = { 22 - ASSETS: { 23 - fetch: () => new Response('ok') 24 - } 25 - }; 26 - 27 - const response = await worker.fetch(request, env); 28 - 29 - assert.strictEqual(response.status, 200); 30 - const body = await response.text(); 31 - assert.strictEqual(body, 'ok'); 32 - }); 33 - 34 - test('ensures percent-encoded sequences are matched as units and remain unchanged while other characters are lowercased', async () => { 35 - const request = new Request('https://example.com/MixEd%20Case%2FPath'); 36 - const env = { 37 - ASSETS: { 38 - fetch: () => new Response('ok') 39 - } 40 - }; 41 - 42 - const response = await worker.fetch(request, env); 43 - 44 - assert.strictEqual(response.status, 301); 45 - // Based on regex /%[0-9A-Fa-f]{2}|[A-Z]/g: 46 - // %20 and %2F match the first part and stay as they are (uppercase hex). 47 - // [A-Z] match the second part and get lowercased. 48 - assert.strictEqual(response.headers.get('Location'), 'https://example.com/mixed%20case%2Fpath'); 49 - }); 50 - 51 - test('handles query parameters correctly', async () => { 52 - const request = new Request('https://example.com/UPPER?query=VAL'); 53 - const env = { 54 - ASSETS: { 55 - fetch: () => new Response('ok') 56 - } 57 - }; 58 - 59 - const response = await worker.fetch(request, env); 60 - 61 - assert.strictEqual(response.status, 301); 62 - // Query parameters should not be touched 63 - assert.strictEqual(response.headers.get('Location'), 'https://example.com/upper?query=VAL'); 64 - });
-2
wrangler.jsonc
··· 1 1 { 2 2 "name": "website", 3 3 "compatibility_date": "2026-03-24", 4 - "main": "src/index.js", 5 4 "assets": { 6 5 "directory": "./_site", 7 6 "binding": "ASSETS", 8 - "run_worker_first": true, 9 7 "html_handling": "auto-trailing-slash", 10 8 "not_found_handling": "404-page" 11 9 },