With the following generic trigger function:
CREATE OR REPLACE FUNCTION allow_updating_only()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
DECLARE
whitelist TEXT[] := TG_ARGV::TEXT[];
schema_table TEXT;
# 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 | |
} |
function chunk<T>(arr: T[], size: number): T[][] { | |
const count = Math.ceil(arr.length / size) | |
let out: T[][] = [] | |
for (let i = 0; i < count; i++) { | |
out.push(arr.slice(count * i, count * (i + 1))) | |
} | |
return out | |
} | |
function chunkString(str: string, size: number): string[] { |
import { parseArgs } from 'node:util' | |
const args = parseArgs({ | |
options: { env: { type: 'string' }, dryRun: { type: 'boolean' } }, | |
}) |
// will act --inspect-brk, but only when evaluated | |
// works inside the main thread, a worker thread | |
// also works with typescript sources, built-in support in tsx | |
require('node:inspector').open(undefined, undefined, true) |
import wretch, { WretchResponse } from 'wretch' | |
import fs from 'node:fs' | |
async function streamWretchResponseToFile( | |
res: WretchResponse, | |
writable: fs.WriteStream, | |
) { | |
if (!res.body) { | |
throw new Error('Response body is null') | |
} |
// Type inference does not work yet | |
export function zMapKeys< | |
Shape extends z.ZodRawShape, | |
T extends z.ZodObject<Shape>, | |
Key extends keyof Shape, | |
MapFn extends <T extends Key>(v: Shape[T], k: T) => PropertyKey, | |
>(schema: T, renameMap: Record<Key, PropertyKey | MapFn>) { | |
const keys = Object.keys(schema.shape) as Key[] | |
return schema.transform((input) => { | |
let output: Record<PropertyKey, any> = {} |
With the following generic trigger function:
CREATE OR REPLACE FUNCTION allow_updating_only()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
DECLARE
whitelist TEXT[] := TG_ARGV::TEXT[];
schema_table TEXT;
Use Caddy (brew install caddy
) to run localhost sites with custom addresses and https certificates.
caddy reverse-proxy --from site.localhost --to localhost:3000
https://site.localhost/
For a more stable config, create a Caddyfile
site.localhost {
reverse_proxy localhost:3000
export type SingletonAsyncFn<Args extends any[], Result> = { | |
getCurrent(): Promise<Result> | null | |
} & ((...args: Args) => Promise<Result>) | |
/** Wrap an async function so only one instance runs at the time | |
* and concurrent calls await the running instance | |
* | |
* @example | |
* const getRand = makeSingletonAsyncFn(() => new Promise<number>(resolve => setTimeout(() => resolve(Math.random()), 1000))) | |
* console.log(await Promise.all([getRand(), getRand()])) // e.g. [0.6214563565449123, 0.6214563565449123] after 1sec |