Skip to content

Instantly share code, notes, and snippets.

@qwtel
qwtel / getFiles.js
Last active September 9, 2023 13:43
[node.js 8+] Recursively get all files in a directory
// Node 8+
// --------------------------------------------------------------
// No external dependencies
const { promisify } = require('util');
const { resolve } = require('path');
const fs = require('fs');
const readdir = promisify(fs.readdir);
const stat = promisify(fs.stat);
@qwtel
qwtel / cf-storage-area.ts
Last active November 8, 2021 01:28
kv-storage implementation for Cloudflare Workers
import { Base64Encoder, Base64Decoder } from 'base64-encoding';
const PREFIX = 'data:application/octet-stream;base64,';
const b64e = new Base64Encoder();
const b64d = new Base64Decoder();
const encodeKey = (key: string | BufferSource) => typeof key !== 'string' ? PREFIX + b64e.encode(key) : key;
const decodeKey = (key: string) => key.startsWith(PREFIX) ? b64d.decode(key.substr(PREFIX.length)) : key;
@qwtel
qwtel / promise-race-truthy.js
Last active October 13, 2021 02:11
Returns the first promise that resolves with a truthy value, or undefined if all promises resolve with a nullish value.
const NEVER = new Promise(() => {});
async function raceTruthy(iterable) {
const ps = [...iterable].map(_ => Promise.resolve(_));
let { length } = ps;
const continueWhenNullish = value => value != null
? value
: --length > 0
? NEVER
: undefined;
@qwtel
qwtel / whatwg-stream-to-async-iterable.ts
Created October 12, 2020 09:02
Convert WHATWG web streams to async iterables and back
export async function* streamToAsyncIterable<T>(stream: ReadableStream<T>): AsyncIterableIterator<T> {
const reader = stream.getReader();
try {
while (true) {
const { done, value } = await reader.read();
if (done) return;
yield value;
}
} finally { reader.releaseLock() }
}
@qwtel
qwtel / README.md
Last active August 12, 2020 04:41
Subtypes of the browser's own Request and Response types adopted for JSON objects.

Main difference to regular Response and Request types is that no manual JSON.stringify and headers.set('Content-Type', ...) is required.

In my opinion, JSONRequest is the most lightweight way of fixing the biggest issue of the Fetch API when dealing with JSON APIs, without resorting to full alternatives such as superagent or axios.

Example:

const response = await fetch(new JSONRequest('/comments', {
  method: 'POST',
 body: { text: 'Usage example: ...' },
@qwtel
qwtel / create-resolvable-promise.ts
Last active June 21, 2020 14:27
TS implementation of a promise that can be resolved after it has been created.
type Resolver<T> = (value: T | PromiseLike<T>) => void;
type Rejector = (reason?: any) => void;
type ResolvablePromise<T> = Promise<T> & { resolve: Resolver<T>, reject: Rejector }
export function createResolvablePromise<T>(): ResolvablePromise<T> {
let res: Resolver<T>
let rej: Rejector;
const promise = new Promise((r, s) => (res = r, rej = s)) as ResolvablePromise<T>;
promise.resolve = res;
promise.reject = rej;
return promise;
@qwtel
qwtel / 10.js
Created December 10, 2019 13:13
const nearestAsteroidsByAngle = pipe(
asteroids.filter(mkNe(laserPos)),
groupBy(mkCalcAngle(laserPos)),
mapValues(ps => ps.sort((p1, p2) => distToLaser(p1) - distToLaser(p2))),
intoMap(),
);
pipe(
cycle([...nearestAsteroidsByAngle.keys()].sort((a, b) => a - b)),
skipWhile(a => a < -Math.PI/2),
@qwtel
qwtel / ParamsURL.js
Last active November 20, 2019 20:35
export class ParamsURL extends URL {
constructor(href, params, origin = globalThis.location) {
super(href, origin);
if (params) {
this.search = new URLSearchParams([...this.searchParams, ...Object.entries(params)]);
}
}
}
export const urlWithParams = (url, params) => {
const u = new URL(url, global.location.origin)
if (params) {
u.search = new URLSearchParams([...u.searchParams, ...Object.entries(params)])
}
return u.href
}
import md5 from "js-md5";
import { base64ToUint8Array, splitUint8Array, concatUint8Arrays } from "./utils";
const HEAD_SIZE_DWORD = 2;
const SALT_SIZE_DWORD = 2;
export async function decryptCryptoJSCipherBase64(
cryptoJSCipherBase64,
password,