Deprecated: Function get_magic_quotes_gpc() is deprecated in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 99
Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 619
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 832
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
{
"version": "https://jsonfeed.org/version/1",
"title": "Articles by François Best",
"home_page_url": "https://francoisbest.com/posts",
"feed_url": "https://francoisbest.com/posts/feed/articles.json",
"description": "I write about TypeScript, Node.js, React, security and privacy.",
"icon": "https://francoisbest.com/favicons/apple-icon-120x120.png",
"author": {
"name": "François Best",
"url": "https://francoisbest.com/"
},
"items": [
{
"id": "/posts/2023/testing-against-every-nextjs-canary-release",
"content_html": "How to run a GitHub Actions workflow when a new pre-release version of Next.js is published.\n\nFull article (6 min read).",
"url": "https://francoisbest.com/posts/2023/testing-against-every-nextjs-canary-release?utm_source=json",
"title": "Testing against every Next.js canary release",
"summary": "How to run a GitHub Actions workflow when a new pre-release version of Next.js is published.",
"image": "https://francoisbest.com/posts/2023/testing-against-every-nextjs-canary-release/opengraph-image-7h4dih.png",
"date_modified": "2023-11-06T00:00:00.000Z",
"date_published": "2023-11-06T00:00:00.000Z",
"author": {
"name": "François Best",
"url": "https://francoisbest.com/"
},
"tags": [
"next.js",
"github-actions",
"testing"
]
},
{
"id": "/posts/2023/publish-a-json-schema",
"content_html": "Improving DX in editors is only half the story.\n\nFull article (3 min read).",
"url": "https://francoisbest.com/posts/2023/publish-a-json-schema?utm_source=json",
"title": "Publish a JSON Schema",
"summary": "Improving DX in editors is only half the story.",
"image": "https://francoisbest.com/posts/2023/publish-a-json-schema/opengraph-image-2njqy7.png",
"date_modified": "2023-10-12T00:00:00.000Z",
"date_published": "2023-10-12T00:00:00.000Z",
"author": {
"name": "François Best",
"url": "https://francoisbest.com/"
},
"tags": [
"json-schema",
"nodejs"
]
},
{
"id": "/posts/2023/dotenv-is-dead",
"content_html": "Long live type-safe environment variable management in Node.js\n\nFull article (3 min read).",
"url": "https://francoisbest.com/posts/2023/dotenv-is-dead?utm_source=json",
"title": "Dotenv is dead",
"summary": "Long live type-safe environment variable management in Node.js",
"image": "https://francoisbest.com/posts/2023/dotenv-is-dead/opengraph-image-1ad5cn.png",
"date_modified": "2023-10-02T00:00:00.000Z",
"date_published": "2023-10-02T00:00:00.000Z",
"author": {
"name": "François Best",
"url": "https://francoisbest.com/"
},
"tags": [
"til",
"nodejs",
"env"
]
},
{
"id": "/posts/2023/displaying-local-times-in-nextjs",
"content_html": "Making time accessible by dealing with React SSR hydration mismatches across timezones.\n\nFull article (4 min read).",
"url": "https://francoisbest.com/posts/2023/displaying-local-times-in-nextjs?utm_source=json",
"title": "Displaying Local Times in Next.js",
"summary": "Making time accessible by dealing with React SSR hydration mismatches across timezones.",
"image": "https://francoisbest.com/posts/2023/displaying-local-times-in-nextjs/opengraph-image-520618.png",
"date_modified": "2023-09-27T08:00:00.000Z",
"date_published": "2023-09-27T08:00:00.000Z",
"author": {
"name": "François Best",
"url": "https://francoisbest.com/"
},
"tags": [
"til",
"next.js",
"react",
"ssr",
"rsc"
]
},
{
"id": "/posts/2023/npm-download-stats-are-down",
"content_html": "And people are drawing the funniest conclusions.\n\nFull article (2 min read).",
"url": "https://francoisbest.com/posts/2023/npm-download-stats-are-down?utm_source=json",
"title": "NPM download stats are down",
"summary": "And people are drawing the funniest conclusions.",
"image": "https://francoisbest.com/posts/2023/npm-download-stats-are-down/opengraph-image-2ebvo2.png",
"date_modified": "2023-09-21T00:00:00.000Z",
"date_published": "2023-09-21T00:00:00.000Z",
"author": {
"name": "François Best",
"url": "https://francoisbest.com/"
},
"tags": [
"npm"
]
},
{
"id": "/posts/2023/storing-react-state-in-the-url-with-nextjs",
"content_html": "A peek under the hood of the next-usequerystate 1.8.x update with support for the app router.\n\nFull article (7 min read).",
"url": "https://francoisbest.com/posts/2023/storing-react-state-in-the-url-with-nextjs?utm_source=json",
"title": "Storing React state in the URL with Next.js",
"summary": "A peek under the hood of the next-usequerystate 1.8.x update with support for the app router.",
"image": "https://francoisbest.com/posts/2023/storing-react-state-in-the-url-with-nextjs/opengraph-image-1t8hxb.png",
"date_modified": "2023-09-20T00:00:00.000Z",
"date_published": "2023-09-20T00:00:00.000Z",
"author": {
"name": "François Best",
"url": "https://francoisbest.com/"
},
"tags": [
"next.js",
"react",
"typescript"
]
},
{
"id": "/posts/2023/reading-files-on-vercel-during-nextjs-isr",
"content_html": "A little hack to let the Next.js file tracer pick up relative file paths.\n\nFull article (2 min read).",
"url": "https://francoisbest.com/posts/2023/reading-files-on-vercel-during-nextjs-isr?utm_source=json",
"title": "Reading files on Vercel during Next.js ISR",
"summary": "A little hack to let the Next.js file tracer pick up relative file paths.",
"image": "https://francoisbest.com/posts/2023/reading-files-on-vercel-during-nextjs-isr/opengraph-image-5rau3n.jpg",
"date_modified": "2023-09-16T00:00:00.000Z",
"date_published": "2023-09-16T00:00:00.000Z",
"author": {
"name": "François Best",
"url": "https://francoisbest.com/"
},
"tags": [
"til",
"next.js",
"vercel",
"rsc"
]
},
{
"id": "/posts/2023/displaying-the-right-vercel-deployment-urls-in-nextjs",
"content_html": "A TIL about caching, Git branch management and React Server Components.\n\nFull article (4 min read).",
"url": "https://francoisbest.com/posts/2023/displaying-the-right-vercel-deployment-urls-in-nextjs?utm_source=json",
"title": "Displaying the right Vercel deployment URLs in Next.js",
"summary": "A TIL about caching, Git branch management and React Server Components.",
"image": "https://francoisbest.com/posts/2023/displaying-the-right-vercel-deployment-urls-in-nextjs/opengraph-image-2y7azx.jpg",
"date_modified": "2023-09-09T00:00:00.000Z",
"date_published": "2023-09-09T00:00:00.000Z",
"author": {
"name": "François Best",
"url": "https://francoisbest.com/"
},
"tags": [
"til",
"rsc",
"git",
"next.js",
"turborepo",
"vercel"
]
},
{
"id": "/posts/2021/hashvatars",
"content_html": "How to turn 256 bits of entropy into a beautiful, avatar-friendly circular SVG: the Hashvatar.\n\nFull article (12 min read).",
"url": "https://francoisbest.com/posts/2021/hashvatars?utm_source=json",
"title": "Representing SHA-256 Hashes As Avatars",
"summary": "How to turn 256 bits of entropy into a beautiful, avatar-friendly circular SVG: the Hashvatar.",
"image": "https://francoisbest.com/posts/2021/hashvatars/opengraph-image-aql0c0.jpg",
"date_modified": "2021-04-18T00:00:00.000Z",
"date_published": "2021-04-18T00:00:00.000Z",
"author": {
"name": "François Best",
"url": "https://francoisbest.com/"
},
"tags": [
"cryptography",
"svg"
]
},
{
"id": "/posts/2021/cargo-docker-mtime",
"content_html": "The perils of premature optimisation in detecting modified source files when building Docker images for Rust.\n\nFull article (4 min read).",
"url": "https://francoisbest.com/posts/2021/cargo-docker-mtime?utm_source=json",
"title": "Cargo, Docker and mtime",
"summary": "The perils of premature optimisation in detecting modified source files when building Docker images for Rust.",
"image": "https://francoisbest.com/posts/2021/cargo-docker-mtime/opengraph-image-3fykr9.jpg",
"date_modified": "2021-01-25T00:00:00.000Z",
"date_published": "2021-01-25T00:00:00.000Z",
"author": {
"name": "François Best",
"url": "https://francoisbest.com/"
},
"tags": [
"rust",
"docker"
]
},
{
"id": "/posts/2020/mobile-device-frames-for-excalidraw",
"content_html": "Building mobile UI mockups in Excalidraw is a lot of fun, but eye-balling screen ratios is not great. Here are some free resources to help you get started, and a guide on how to make your own frames.\n\nFull article (3 min read).",
"url": "https://francoisbest.com/posts/2020/mobile-device-frames-for-excalidraw?utm_source=json",
"title": "Mobile Device Frames For Excalidraw",
"summary": "Building mobile UI mockups in Excalidraw is a lot of fun, but eye-balling screen ratios is not great. Here are some free resources to help you get started, and a guide on how to make your own frames.",
"image": "https://francoisbest.com/posts/2020/mobile-device-frames-for-excalidraw/opengraph-image-2ujlx6.jpg",
"date_modified": "2020-06-11T00:00:00.000Z",
"date_published": "2020-06-11T00:00:00.000Z",
"author": {
"name": "François Best",
"url": "https://francoisbest.com/"
},
"tags": [
"excalidraw",
"ui-design"
]
},
{
"id": "/posts/2020/dark-mode-for-excalidraw",
"content_html": "How to give a dark twist to Excalidraw diagrams with CSS filters.\n\nFull article (3 min read).",
"url": "https://francoisbest.com/posts/2020/dark-mode-for-excalidraw?utm_source=json",
"title": "Dark Mode For Excalidraw",
"summary": "How to give a dark twist to Excalidraw diagrams with CSS filters.",
"image": "https://francoisbest.com/posts/2020/dark-mode-for-excalidraw/opengraph-image-fdfkxf.jpg",
"date_modified": "2020-06-05T00:00:00.000Z",
"date_published": "2020-06-05T00:00:00.000Z",
"author": {
"name": "François Best",
"url": "https://francoisbest.com/"
},
"tags": [
"frontend",
"css",
"excalidraw"
]
},
{
"id": "/posts/2020/the-security-of-github-actions",
"content_html": "GitHub Actions are a great way to build powerful customised CI/CD workflows using the power of community-driven resources, but they can be tricky to get right in terms of security.\n\nFull article (9 min read).",
"url": "https://francoisbest.com/posts/2020/the-security-of-github-actions?utm_source=json",
"title": "The Security of GitHub Actions",
"summary": "GitHub Actions are a great way to build powerful customised CI/CD workflows using the power of community-driven resources, but they can be tricky to get right in terms of security.",
"image": "https://francoisbest.com/posts/2020/the-security-of-github-actions/opengraph-image-uguro0.jpg",
"date_modified": "2020-02-24T00:00:00.000Z",
"date_published": "2020-02-24T00:00:00.000Z",
"author": {
"name": "François Best",
"url": "https://francoisbest.com/"
},
"tags": [
"security",
"tooling",
"github-actions",
"docker"
]
},
{
"id": "/posts/2020/password-reset-for-e2ee-apps",
"content_html": "We forget passwords. Usually it's OK, because most websites implement a password reset feature. But how to do this in end-to-end encrypted applications that don't have access to the password in the first place ?\n\nFull article (5 min read).",
"url": "https://francoisbest.com/posts/2020/password-reset-for-e2ee-apps?utm_source=json",
"title": "Password Reset for End-to-End Encrypted Applications",
"summary": "We forget passwords. Usually it's OK, because most websites implement a password reset feature. But how to do this in end-to-end encrypted applications that don't have access to the password in the first place ?",
"image": "https://francoisbest.com/posts/2020/password-reset-for-e2ee-apps/opengraph-image-1al033.jpg",
"date_modified": "2020-02-15T00:00:00.000Z",
"date_published": "2020-02-15T00:00:00.000Z",
"author": {
"name": "François Best",
"url": "https://francoisbest.com/"
},
"tags": [
"e2ee",
"security",
"cryptography"
]
},
{
"id": "/posts/2019/how-to-store-e2ee-keys-in-the-browser",
"content_html": "End-to-end encrypted applications use cryptographic keys that don't leave the client, so how do we store them securely in the browser ?\n\nFull article (4 min read).",
"url": "https://francoisbest.com/posts/2019/how-to-store-e2ee-keys-in-the-browser?utm_source=json",
"title": "How To Store End-to-End Encryption Keys In The Browser",
"summary": "End-to-end encrypted applications use cryptographic keys that don't leave the client, so how do we store them securely in the browser ?",
"image": "https://francoisbest.com/posts/2019/how-to-store-e2ee-keys-in-the-browser/opengraph-image-39g9ol.jpg",
"date_modified": "2019-12-13T00:00:00.000Z",
"date_published": "2019-12-13T00:00:00.000Z",
"author": {
"name": "François Best",
"url": "https://francoisbest.com/"
},
"tags": [
"e2ee",
"security"
]
},
{
"id": "/posts/2019/strava-auth-cli-in-rust",
"content_html": "A first look at how to implement an OAuth authentication / authorization exchange in Rust.\n\nFull article (14 min read).",
"url": "https://francoisbest.com/posts/2019/strava-auth-cli-in-rust?utm_source=json",
"title": "Building A Strava Authentication CLI In Rust",
"summary": "A first look at how to implement an OAuth authentication / authorization exchange in Rust.",
"image": "https://francoisbest.com/posts/2019/strava-auth-cli-in-rust/opengraph-image-2gs6w5.jpg",
"date_modified": "2019-01-15T00:00:00.000Z",
"date_published": "2019-01-15T00:00:00.000Z",
"author": {
"name": "François Best",
"url": "https://francoisbest.com/"
},
"tags": [
"rust",
"strava"
]
}
]
}