Skip to content

Instantly share code, notes, and snippets.

View borispoehland's full-sized avatar

Boris Pöhland borispoehland

View GitHub Profile
@borispoehland
borispoehland / pause_all.ts
Last active February 28, 2024 14:47
Vercel Webhook to call to pause the project after the spending limit is reached
import crypto from 'crypto'
const { INTEGRATION_SECRET, VERCEL_TEAM_ID, VERCEL_TOKEN } = process.env
function sha1(data: Buffer, secret: string): string {
return crypto.createHmac('sha1', secret).update(data).digest('hex')
}
export async function POST(request: Request) {
if (typeof INTEGRATION_SECRET != 'string') {
@borispoehland
borispoehland / Await.tsx
Created January 13, 2024 08:26
Next.js 14 + React RSC Signout flow using efficient data fetching with <Await />
import { Thenable } from "react";
export async function Await<T>({
promise,
children,
}: {
promise: Thenable<T>;
children: (value: T) => JSX.Element;
}) {
const data = await promise;
import {
ElementRef,
ForwardRefExoticComponent,
createElement,
forwardRef,
} from "react";
import { cn } from "./utils";
export function extend<T extends { className?: string }>(
Component: ForwardRefExoticComponent<T>,
@borispoehland
borispoehland / useAppQuery.ts
Created September 10, 2023 05:23
Wrap react-query with a per-hook way to invalidate and set queries
import type { SetStateAction } from 'react'
import { useCallback } from 'react'
import type { QueryFunction, UseQueryOptions } from 'react-query'
import { useQuery, useQueryClient } from 'react-query'
type IQueryMutator<T> = (value: SetStateAction<T>) => void
type IOptions<T> =
| Omit<UseQueryOptions<T, unknown, T, string[]>, 'queryKey' | 'queryFn'>
Effect.flatMap(({ id }) => {
const program = fetchFresh(
pollSchema,
`https://graph.facebook.com/${id}${objectToQueryString({
fields: 'status_code',
access_token: FACEBOOK_PAGE_TOKEN,
})}`
)
return Effect.repeatUntilEffect(program, (props) => {
import type { FiberId, FiberRefs, HashMap, List } from 'effect'
import { Cause, Effect, Logger, pipe } from 'effect'
import type { AnnotationValue } from 'effect/Logger'
import type { LogLevel } from 'effect/LoggerLevel'
import type { LogSpan } from 'effect/LoggerSpan'
import pino from 'pino'
import type { WithRequired } from '@/types/helpers'
const pinoLogger = pino()
const getAccessToken = fetchFresh<{ access_token: string }>(
null,
'https://accounts.spotify.com/api/token',
{
method: 'POST',
headers: {
Authorization: `Basic ${Buffer.from(
`${process.env.SPOTIFY_CLIENT_ID}:${process.env.SPOTIFY_CLIENT_SECRET}`
).toString('base64')}`,
'Content-Type': 'application/x-www-form-urlencoded',
async function getAccessToken() {
return Effect.runPromise(
fetchFresh<{ access_token: string }>(
null,
'https://accounts.spotify.com/api/token',
{
method: 'POST',
headers: {
Authorization: `Basic ${Buffer.from(
`${process.env.SPOTIFY_CLIENT_ID}:${process.env.SPOTIFY_CLIENT_SECRET}`
@borispoehland
borispoehland / effects.ts
Last active March 3, 2024 08:48
3 fetch effects for effect-ts. One uses cache: no-store, one cache: force-cache and one uses the default cache / revalidate
import * as S from '@effect/schema/Schema'
import { Context, Effect } from 'effect'
export interface IFetcher {
fetch: typeof fetch
}
export const TFetcher = Context.Tag<IFetcher>('IFetcher')
class FreshFetcher implements IFetcher {
{
"version": 2,
"builds": [
{
"src": "src/app.js",
"use": "@vercel/node"
}
],
"routes": [
{