podcast manager
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

some cleanup and types

+48 -14
+16 -4
src/common/aborts.ts
··· 7 7 controller.abort(new DOMException("Operation timed out", "TimeoutError")); 8 8 }, ms); 9 9 10 - const cleanup = () => clearTimeout(timeout); 11 - controller.signal.addEventListener("abort", cleanup); 10 + const cleanup = () => { 11 + clearTimeout(timeout); 12 + controller.signal.removeEventListener("abort", cleanup); 13 + }; 12 14 15 + controller.signal.addEventListener("abort", cleanup); 13 16 return { signal: controller.signal, cleanup }; 14 17 } 15 18 16 19 export function combineSignals(...signals: AbortSignal[]): AbortSignal { 17 20 const controller = new AbortController(); 21 + const cleanups = [] as (() => void)[]; 18 22 19 23 for (const signal of signals) { 20 24 if (signal.aborted) { 21 25 controller.abort(signal.reason); 22 26 return controller.signal; 23 27 } 24 - signal.addEventListener("abort", () => { 28 + 29 + const handler = () => { 25 30 if (!controller.signal.aborted) { 26 31 controller.abort(signal.reason); 27 32 } 28 - }); 33 + }; 34 + 35 + signal.addEventListener("abort", handler); 36 + cleanups.push(() => signal.removeEventListener("abort", handler)); 29 37 } 38 + 39 + controller.signal.addEventListener("abort", () => { 40 + cleanups.forEach((cb) => cb()); 41 + }); 30 42 31 43 return controller.signal; 32 44 }
+1 -1
src/common/crypto-algos.ts
··· 1 1 // TODO, is there a better way of getting the algo type? 2 2 export type Algo = Parameters<typeof crypto.subtle.importKey>[2]; 3 3 export const encrAlgo = { name: "AES-GCM", length: 256 } satisfies Algo; 4 - export const signAlgo = { name: "ECDSA", namedCurve: "P-256" } satisfies Algo; 4 + export const signAlgo = { name: "ES256" } satisfies Algo;
+9 -9
src/common/crypto-sig.ts
··· 99 99 100 100 export const serializedJwkPairSchema = z.object({ 101 101 __type: z.literal("jwkpair"), 102 - publicJwk: z.any(), 103 - privateJwk: z.any(), 102 + publicKey: z.any(), 103 + privateKey: z.any(), 104 104 }); 105 105 106 106 export type SerializedJwkPair = z.infer<typeof serializedJwkPairSchema>; ··· 110 110 } 111 111 112 112 export async function serializeJwkPair(jwks: CryptoKeyPair): Promise<SerializedJwkPair> { 113 - const [publicJwk, privateJwk] = await Promise.all([ 113 + const [publicKey, privateKey] = await Promise.all([ 114 114 exportJWK(jwks.publicKey), 115 115 exportJWK(jwks.privateKey), 116 116 ]); 117 117 118 118 return { 119 119 __type: "jwkpair", 120 - publicJwk, 121 - privateJwk, 120 + publicKey, 121 + privateKey, 122 122 }; 123 123 } 124 124 125 125 export async function deserializeJwkPair(data: unknown): Promise<CryptoKeyPair> { 126 - const { publicJwk, privateJwk } = serializedJwkPairSchema.parse(data); 127 - const [publicKey, privateKey] = await Promise.all([ 128 - importJWK(publicJwk, signAlgo.name, { extractable: true }) as Promise<CryptoKey>, 129 - importJWK(privateJwk, signAlgo.name, { extractable: true }) as Promise<CryptoKey>, 126 + let { publicKey, privateKey } = serializedJwkPairSchema.parse(data); 127 + [publicKey, privateKey] = await Promise.all([ 128 + importJWK(publicKey, signAlgo.name, { extractable: true }) as Promise<CryptoKey>, 129 + importJWK(privateKey, signAlgo.name, { extractable: true }) as Promise<CryptoKey>, 130 130 ]); 131 131 132 132 return {
+20
src/common/sleep.ts
··· 1 + export function sleep(ms: number, signal?: AbortSignal) { 2 + signal?.throwIfAborted(); 3 + 4 + const { resolve, reject, promise } = Promise.withResolvers<void>(); 5 + const timeout = setTimeout(resolve, ms); 6 + 7 + if (signal) { 8 + const abortHandler = () => { 9 + clearTimeout(timeout); 10 + reject(signal.reason); 11 + }; 12 + 13 + signal.addEventListener("abort", abortHandler); 14 + promise.finally(() => { 15 + signal.removeEventListener("abort", abortHandler); 16 + }); 17 + } 18 + 19 + return promise; 20 + }
+2
src/types/replace.ts
··· 1 + /** replace a key with a different type */ 2 + export type Replace<T, K extends keyof T, U> = Omit<T, K> & Record<K, U>;