Skip to content

Instantly share code, notes, and snippets.

View lubieowoce's full-sized avatar
☀️

Janka Uryga lubieowoce

☀️
View GitHub Profile
@lubieowoce
lubieowoce / track-thenable-state.ts
Created April 14, 2025 11:36
trackThenableState
export type Thenable<T> =
| PendingThenable<T>
| FulfilledThenable<T>
| RejectedThenable<T>
type PendingThenable<T> = Promise<T> & { status: 'pending' }
type FulfilledThenable<T> = Promise<T> & { status: 'fulfilled'; value: T }
type RejectedThenable<T> = Promise<T> & { status: 'rejected'; reason: unknown }
export function trackThenableState<T>(promise: Promise<T>): Thenable<T> {
@lubieowoce
lubieowoce / try-catch.ts
Created April 14, 2025 01:09
try-catch-finally, sync and async
/** A `try-catch-finally` that works for both sync and async callbacks. */
export function tryCatch<T>(
cb: () => T | Promise<T>,
options: { catch?: (error: unknown) => T; finally?: () => void }
): T {
const { catch: onCatch, finally: onFinally } = options
let isAsync = false
try {
const result = cb()
@lubieowoce
lubieowoce / picosky-snippets.js
Created October 1, 2024 22:15
snippets for posting stuff in picosky
// https://pico.bsky.mom/
(async () => {
// sine
const lines = 24
function sine(t) {
const w = 12;
const arr = new Array(12).fill('.');
const ix = Math.floor(((Math.cos(t * 0.6) + 1) / 2) * w);
arr[ix] = '#';
@lubieowoce
lubieowoce / replace.ts
Created July 30, 2024 12:24
Change type of object property while preserving JSDoc
type Replace<
Obj extends Record<string, any>,
Field extends keyof Obj,
NewType,
> = Reveal<
{ [Key in keyof Obj]: Key extends Field ? NewType : Obj[Key] }
>
type Reveal<Obj extends Record<string, any>> = {
[K in keyof Obj]: Obj[K]
export type Thenable<T> = PendingThenable<T> | FulfilledThenable<T> | RejectedThenable<T>
export type PendingThenable<T> = Promise<T> & { status: 'pending' }
export type FulfilledThenable<T> = Promise<T> & { status: 'fulfilled', value: T }
export type RejectedThenable<T> = Promise<T> & { status: 'rejected', reason: unknown }
export function trackThenableState<T>(promise: Promise<T>): Thenable<T> {
const thenable = promise as Thenable<T>;
if ("status" in thenable && typeof thenable.status === "string") {
@lubieowoce
lubieowoce / cache-value.ts
Created February 14, 2024 20:32
We have Record/Tuple at home
/// <reference types="react/canary" />
import React, { cache } from "react";
type Options = { passthrough?: boolean };
const OPTIONS_DEFAULT: Options = { passthrough: false };
type RecordOrTupleArg = Record<string, any> | any[]
export function cacheValue<TObj extends RecordOrTupleArg>(
v: RecordOrTupleArg,
@lubieowoce
lubieowoce / read-rsc-payload.js
Last active July 31, 2024 17:03
Extract the RSC payload from the HTML of a Next.js site
(() => {
const env = { self: {} };
const chunks = Array.from(document.body.querySelectorAll("script"))
.filter((s) => !!s.textContent && s.textContent.includes("self.__next_f"))
.forEach((s) => new Function("self", s.textContent)(env.self));
return env.self.__next_f
.filter((c) => c[0] === 1)
.map((c) => c[1])
.join("");
})();
@lubieowoce
lubieowoce / next+14.0.1.patch
Last active October 30, 2023 22:17
Next 14.0.1: log more details for "This is not allowed due to cyclic module graph between Server and Client"
diff --git a/node_modules/next/dist/build/webpack/loaders/next-flight-loader/index.js b/node_modules/next/dist/build/webpack/loaders/next-flight-loader/index.js
index 59e02e7..0bf857b 100644
--- a/node_modules/next/dist/build/webpack/loaders/next-flight-loader/index.js
+++ b/node_modules/next/dist/build/webpack/loaders/next-flight-loader/index.js
@@ -43,6 +43,7 @@ function transformSource(source, sourceMap) {
// and we shouldn't error for that. In the future we might want to find a way
// to only throw when it's used.
if (!this.resourcePath.includes("node_modules")) {
+ console.log('uh oh:', this._module.resourceResolveData.context.issuer, '->', this._module.resource)
this.callback(new Error(`You're importing a Client Component ("use client") from another Client Component imported Server Action file ("use server"). This is not allowed due to cyclic module graph between Server and Client.\nYou can work around it by defining and passing this
@lubieowoce
lubieowoce / babel-plugin-inline-actions.cjs
Last active October 28, 2023 22:07
a naive and WIP babel transform for inline "use server" closures
// @ts-check
/* eslint-disable @typescript-eslint/no-var-requires */
const { declare: declarePlugin } = require("@babel/helper-plugin-utils");
const { addNamed } = require("@babel/helper-module-imports");
const crypto = require("node:crypto");
const { pathToFileURL } = require("node:url");
// TODO: handle inline actions calling each other...? sounds tricky...

Let's assume we wanna show a tree like this:

ServerRoot # RSC
  html
    body
      MyLayout # RSC
        main
          "Hello"