Skip to content

Instantly share code, notes, and snippets.

View richardscarrott's full-sized avatar

Richard Scarrott richardscarrott

View GitHub Profile
@richardscarrott
richardscarrott / worker.ts
Last active August 25, 2023 19:17
Cloudflare Workers / Pages `stale-while-revalidate`
import { parse } from 'cache-control-parser';
export default {
async fetch(request: Request, env: {}, ctx: ExecutionContext): Promise<Response> {
try {
const cache = await caches.default;
const cachedResponse = await cache.match(request);
if (cachedResponse) {
console.log('Cache: HIT');
if (shouldRevalidate(cachedResponse)) {
@richardscarrott
richardscarrott / portal.tsx
Last active November 8, 2022 11:11
React portal implementation supporting enter / exit animations
import React, {
createContext,
useState,
useCallback,
useMemo,
useContext,
useId,
useLayoutEffect,
useEffect,
} from "react";
@richardscarrott
richardscarrott / request-next-animation-frame.ts
Last active October 18, 2022 10:19
Utility to enqueue + cancel callback for *next* animation frame (Double rAF)
const requestNextAnimationFrame = (callback: FrameRequestCallback) => {
const handles: number[] = [];
const requestThisAnimationFrame = (callback: FrameRequestCallback) => {
handles.push(window.requestAnimationFrame(callback));
};
requestThisAnimationFrame(() => requestThisAnimationFrame(callback));
return () => handles.forEach(handle => window.cancelAnimationFrame(handle));
};
@richardscarrott
richardscarrott / TError.ts
Last active September 5, 2022 13:51
Modern VError
interface TErrorOptions<Info, Cause> {
readonly msg?: string;
readonly info?: Info;
readonly cause?: Cause;
}
class TError<Info, Cause extends Error> extends Error {
public info?: Info;
public cause?: Cause;
constructor({ msg, cause, info }: TErrorOptions<Info, Cause>) {
@richardscarrott
richardscarrott / ___README.md
Last active July 31, 2022 12:08
Simple middleware stack for next.js getServerSideProps (and eventually Api Routes)

Next.js use

Simple middleware stack for next.js getServerSideProps (and eventually Api Routes)

import { use, wrap, Middleware } from './use';

interface WithUserVars {
   users?: User;
}
@richardscarrott
richardscarrott / with-transaction.ts
Created June 25, 2021 10:12
MongoDB withTransaction
// The docs for mongodb native driver sessions are pretty bare. The best example I can find is
// https://www.mongodb.com/blog/post/quick-start-nodejs--mongodb--how-to-implement-transactions
// but the code is generally not pretty; I think the following is likely the most suitable API:
// const doc = withTransaction(async session => {
// const doc = await users.updateOne({ _id: id }, { $set: { email } }, { returnOriginal: false, session });
// await orders.updateMany({ email }, { $set: { userId: id } }, { session });
// return doc;
// });
const withTransaction = async <T>(
fn: (session: ClientSession) => Promise<T>
@richardscarrott
richardscarrott / to-promise.js
Last active February 16, 2021 13:21
Highlandjs toPromise backpressure
const _ = require("highland");
const { Readable } = require("stream");
const wrapAsync = require("./wrap-async");
const sleep = (duration) =>
new Promise((resolve) => setTimeout(resolve, duration));
class Counter extends Readable {
constructor(opt) {
super(opt);
@richardscarrott
richardscarrott / benchmark.js
Last active May 11, 2020 08:04
Memoize benchmark
// Originally from fast-memoize; updated to include `mem` and test multiple and non-primitive arguments.
const ora = require("ora");
const Table = require("cli-table2");
const debug = require("logdown")();
const lruMemoize = require("lru-memoize").default;
const iMemoized = require("iMemoized");
const Benchmark = require("benchmark");
const underscore = require("underscore").memoize;
const lodash = require("lodash").memoize;
@richardscarrott
richardscarrott / test.js
Created February 6, 2020 16:30
High precision time
const work = () => {
for (let i = 0; i < 1000000; i++) {}
};
const start = process.hrtime.bigint();
work();
const end = process.hrtime.bigint();
console.log(
`Benchmark took ${Number(end - start) / 1000 / 1000 / 1000} seconds`
);
@richardscarrott
richardscarrott / closest.ts
Created January 24, 2020 12:23
closest([1, 2, 6, 0], 5) // 6
const closest = (values: number[], val: number) => {
if (!values.length) {
throw new VError(
{ info: { values, val } },
'Expected values to contain at least one value'
);
}
return values.reduce(
(acc, currVal) =>
Math.abs(acc.delta) > Math.abs(currVal - val)