Skip to content

Instantly share code, notes, and snippets.

View dantman's full-sized avatar

Daniel Friesen dantman

View GitHub Profile
@dantman
dantman / languages.ts
Created October 31, 2026 02:58
Simple hydration-safe React hooks to get the system timezone and language client side
import { useSyncExternalStore } from "react";
/**
* Hook to get the current navigator.languages in a hydration-safe manner.
*
* Returns the current preferred languages as an array of strings, e.g., ["en-US", "fr-FR"].
* On the server, it will always return ["en-US"].
* On the client, it will automatically detect updates to the preferred languages
* if the user changes the browser language settings.
*
@dantman
dantman / README.md
Created October 28, 2026 03:31
Script to generate chatLanguageModels.json models for Vercel AI Gateway Models

Vercel AI Gateway Models generator for chatLanguageModels.json

Sometimes I like using the Vercel AI Gateway in VSCode. If I use up my subscription and need to do something small for a team project I can use a team budget. I can try out models that aren't available on my subscription. And sometimes there are model promotions that are worth trying out.

But constructing the JSON for chatLanguageModels.json for each model is always a pain. So one evening I put together a CLI that lets me search for a model in the Vercel AI Gateway and output the JSON that can be pasted in.

This was built inside of another project so it may need some adapation;

  1. The script depends on the @better-fetch/fetch @clack/prompts consola sort-es supports-color zod packages.
  2. I built this in a mixed CommonJS/ESM project (old codebase still using typescript's CommonJS output for bundles; but with ESM cli scripts to get top-level await) so it uses .mts and a mtsFixImport helper that hacks around how Node.js and TypeScript c
@dantman
dantman / README.md
Last active October 10, 2026 12:31
How-to quickly setup an ephemeral "Self-Hosted" PostHog instance to test API client implementations against

How-to quickly setup an ephemeral "Self-Hosted" PostHog instance to test API client implementations against

I was writing an application that connected to customer PostHog accounts via the PostHog API and wanted to make sure it still worked for self-hosted PostHog users. But it's pretty hard to find any of those, much less ones where I can ask for an API key with Query permission, so I needed to host it myself.

Now I didn't actually want to go and setup any VPS to run this on. I use serverless platforms like Vercel and Convex for the things I write so I don't have access to any VPS-like environment that would be easy to run a series of Docker containers in without much work. So the natural thing I wanted to reach to was a Devcontainer and a temporary localhost tunnel. _No paying for a temporary VPS, Docker just runs on my machine. It all lives inside of a devcontainer so it doesn't polute my local environment, I can easily interact with it t

@dantman
dantman / curl-jq-api-tips.md
Created September 30, 2026 11:16
Tips for making JSON API calls with curl and jq: pretty-printing and paging responses, sending JSON POSTs with --json @-, embedding text like SQL queries with jq -Rs, and a jqless pager function.

Lately I've been making a LOT of API calls with curl, mostly to PostHog's API, and picked up some tricks along the way.

Let's start by trying this:

curl --no-progress-meter --dump-header=% https://xkcd.com/info.0.json | jq .

When APIs return JSON a lot of them don't pretty-print it. Pipe it into jq ., install it if you don't have it, and you'll get the JSON back with both pretty-printing and syntax highlighting.

@dantman
dantman / README.md
Last active October 10, 2026 12:46
isNonNullable utility, allows you to simply write .filter(isNonNullable) on an array to exclude null/undefined and get the correct array type as a result.

isNonNullable

The isNonNullable function is a type guard that filters out null and undefined values from an array.

I've had to do this type assertion inline so many times that I just made it into a reusable utility in most of my projects.

You can use it like this to filter out null and undefined values from an array:

const values = [1, null, 2, undefined, 3];
@dantman
dantman / gist:555b1e2d53591d412545e9cafeae7114
Created September 6, 2026 01:30
Pasteable bash one-shot to temporarily add `./pinact` to a project (e.g. one in a devcontainer) you want to pin GitHub actions in
(
set -e
version="$(gh release view --repo suzuki-shunsuke/pinact --json tagName -q .tagName)"
asset="$(echo "pinact_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')".tar.gz)"
gh release download -R suzuki-shunsuke/pinact "$version" -p "$asset"
gh attestation verify "$asset" \
-R suzuki-shunsuke/pinact \
--signer-workflow suzuki-shunsuke/go-release-workflow/.github/workflows/release.yaml
tar -xzf "$asset" -C . "pinact"
chmod +x ./pinact
@dantman
dantman / header.ts
Created August 31, 2026 22:09
An experimental mini-library for getting an array of the user's language preferences from Accepts-Language/navigator.languages in a way that works without hydration errors and updates when preferences change
import { normalizeLanguageCode } from "./normalize";
/**
* A regexp to separate language tags from their optional q-factor weight in the Accept-Language header.
*/
const DIRECTIVE_REGEX = /^([^;]+)(?:;\s*q\s*=\s*(\d(?:\.\d+)?|\.\d+)\s*)?$/i;
/**
* Represents a single language directive from the Accept-Language header, including its position, normalized language code, and quality factor.
* e.g. "en;q=0.5" as the first word in the header would result in `{ headerIndex: 0, languageCode: "en", q: 0.5 }`.
@dantman
dantman / README.md
Last active September 3, 2026 23:50
Reusable "definedForm" boilerplate

📝 React + Zod + React Hook Form Boilerplate

A reusable pattern for building type-safe, validated forms in React using:

  • react-hook-form: For ergonomic form state management.
  • zod: For schema-based validation and type inference.
  • TypeScript: For full type safety throughout your forms.

Features

  • defineForm(schema): Generates a custom hook for your form, automatically wiring up Zod validation and type inference.
{
"name": "typefabric-management-app",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "typefabric-management-app",
"version": "0.1.0",
"dependencies": {
@dantman
dantman / copilot-instructions.md
Created June 4, 2025 14:05
Prompt to automate Drizzle migration process

An AI agent should attempt to run cli commands on behalf of the user when they are needed.

Before running any command as a terminal command, the AI agent should check if there is a relevant MCP (Machine Command Protocol) command available in the project. If there is, it should use that instead of running a terminal command directly.

Check type safety using the npm run typecheck task instead of tsc directly.

Drizzle

The database schema can be found in schema.ts. For timestamp and date column types use { mode: "date" } to give the column the Date type.