Skip to content

Instantly share code, notes, and snippets.

View christophemarois's full-sized avatar

Christophe Marois christophemarois

View GitHub Profile
@christophemarois
christophemarois / tryit.ts
Last active December 18, 2024 16:15
tryit.ts
// adapted from https://jsr.io/@backend/safe-assignment
type WithErrResultPlain<T> = [Error, null] | [null, T]
type WithErrResult<T> = T extends Promise<infer U>
? Promise<WithErrResultPlain<U>>
: WithErrResultPlain<T>
type WithErr<T> = T extends Promise<unknown>
? WithErrResult<T>
: T extends () => infer U
@christophemarois
christophemarois / createTypedContext.ts
Created December 3, 2024 16:10
createTypedContext
/** Typed context creation helper
* @example
* export const [useLevel, LevelProvider] = createTypedContext<{ level: number }>('LevelContext')
*/
export function createTypedContext<T>(name: string) {
const Context = createContext<T | null>(null)
function useEnsuredContext() {
const ctx = useContext(Context)
if (ctx === null) {
/* eslint-disable no-console */
/**
* Represents a deeply readonly version of a type, including nested objects,
* arrays, sets, and maps.
* @template T - The type to make deeply readonly.
*/
export type DeepReadonly<T> = T extends (infer R)[]
? ReadonlyArray<DeepReadonly<R>>
: T extends Set<infer R>
? ReadonlySet<DeepReadonly<R>>
/** Create a wrapped AbortController that is aborted when a SIGINT/SIGTERM is received.
* Supports auto-unregistering via explicit resource management.
*
* @example
* using shutdownSignal = new ShutdownSignal()
* shutdownSignal.throwIfAborted()
*
* // or
* const shutdownSignal = new ShutdownSignal()
* try { shutdownSignal.throwIfAborted() } finally { shutdownSignal.unregister() }
@christophemarois
christophemarois / cloudflare-tunnels.md
Last active April 9, 2024 13:24
Cloudflare Tunnels

Cloudflare is a better and free ngrok. With a domain that uses it, set it up like this

  1. Setup a tunnel
cloudflared tunnel login
cloudflared tunnel create test
cloudflared tunnel route dns test test.christophemarois.com
@christophemarois
christophemarois / redactPasswordFromUrl.ts
Created March 7, 2024 15:08
redactPasswordFromUrl.ts
/** Transform the password part of a connection string URL into [redacted].
* Useful for logging. */
export function redactPasswordFromUrl(url: string) {
return url.replace(/^([^:]+):\/\/([^:]*):([^@]+)@/, '$1://$2:[redacted]@')
}
@christophemarois
christophemarois / icloud-cal-in-thunderbird.md
Last active October 10, 2023 13:43
Icloud calendars in Thunderbird
  1. Create an app-specific password for iCloud account (check Bitwarden notes)
  2. Use https://github.com/midnightmonster/icloud-calendar-urls to get your calendar's secret URL
curl -s https://raw.githubusercontent.com/midnightmonster/icloud-calendar-urls/master/icloud_calendar_urls | bash
  1. In thunderbird, add calendar with your icloud username, secret url and app-specific password
@christophemarois
christophemarois / node-monitoring.md
Last active October 2, 2023 13:50
Node Grafana/Prometheus Performance Monitoring

Monitor in Node (PerformanceObserver is not yet implemented in Bun. in bun 1.0.3)

import { collectDefaultMetrics, register } from 'prom-client'

if (req.method === 'GET' && pathname === '/metrics/') {
  return new Response(await register.metrics(), {
    headers: {
      'Content-Type': register.contentType,
 },
@christophemarois
christophemarois / zod-unique-array.ts
Created September 29, 2023 23:04
Zod Unique Array
/** Array where are elements are expected to be unique by a custom key */
export function zUniqueArray<
ArrSchema extends z.ZodArray<z.ZodTypeAny, 'many'>,
UniqueVal,
>(
uniqueBy: (item: z.infer<ArrSchema>[number]) => UniqueVal,
schema: ArrSchema,
) {
return schema.superRefine((items, ctx) => {
const seen = new Set<UniqueVal>()
@christophemarois
christophemarois / git_list_branch_changes.sh
Created September 15, 2023 12:57
List branch changes in git
# list changed files in a branch compared to its base branch
# usage: git_list_branch_changes [base_branch?] | xargs echo
function git_list_branch_changes {
local BASE_BRANCH="${1:-main}"
(git diff --diff-filter=MA --name-only $BASE_BRANCH... && git status --short --porcelain | awk '{print $2}') | sort -u
}