Skip to content

Commit

Permalink
fix: createAction
Browse files Browse the repository at this point in the history
  • Loading branch information
nahoc committed Oct 10, 2024
1 parent 4d44d4c commit 570b14e
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 2 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ https://www.npmjs.com/package/@risc0/ui

| Statements | Branches | Functions | Lines |
| --------------------------- | ----------------------- | ------------------------- | ----------------- |
| ![Statements](https://img.shields.io/badge/statements-38.25%25-red.svg?style=flat) | ![Branches](https://img.shields.io/badge/branches-80.48%25-yellow.svg?style=flat) | ![Functions](https://img.shields.io/badge/functions-73.46%25-red.svg?style=flat) | ![Lines](https://img.shields.io/badge/lines-38.25%25-red.svg?style=flat) |
| ![Statements](https://img.shields.io/badge/statements-36.69%25-red.svg?style=flat) | ![Branches](https://img.shields.io/badge/branches-79.51%25-red.svg?style=flat) | ![Functions](https://img.shields.io/badge/functions-72%25-red.svg?style=flat) | ![Lines](https://img.shields.io/badge/lines-36.69%25-red.svg?style=flat) |
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@risc0/ui",
"version": "0.0.187",
"version": "0.0.188",
"private": false,
"sideEffects": false,
"type": "module",
Expand Down Expand Up @@ -37,6 +37,7 @@
"cmdk": "1.0.0",
"lucide-react": "0.451.0",
"next-themes": "0.3.0",
"p-safe": "1.0.0",
"radash": "12.1.0",
"react-hook-form": "7.52.2",
"recharts": "2.13.0-alpha.5",
Expand Down
91 changes: 91 additions & 0 deletions utils/action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import type { SafeReturn } from "p-safe";

export class ActionError extends Error {
override name = "ActionError";
constructor(
public code: string,
message: string,
) {
super(message);
Error.captureStackTrace(this, ActionError);
}

toPlain(): ActionErrorPlain {
return {
code: this.code,
message: this.message,
};
}
}

export interface ActionErrorPlain {
code: string;
message: string;
}

type AnyFunc<This = void> = (this: This, ...args: readonly any[]) => unknown;

type ActionFunc<T> = T extends (...args: infer Args) => infer Return
? (this: any, ...args: Args) => Promise<SafeReturn<Awaited<Return>, ActionError>>
: never;

interface ActionContext<Return> {
resolve: (result: Return) => never;
reject: (error: ActionErrorPlain | ActionError) => never;
}

class Action<Return> {
#fn: AnyFunc<ActionContext<any>>;

constructor(fn: AnyFunc<ActionContext<any>>) {
this.#fn = fn;
}

resolve(result: Return): never {
throw { data: result };
}

reject(reason: ActionErrorPlain | ActionError): never {
throw reason;
}

/** @internal */
async run(...arguments_: any[]) {
try {
const result_ = await this.#fn.apply(this, arguments_); // eslint-disable-line prefer-spread
if (result_ !== undefined) {
return { data: result_ };
}
return { data: void 0 };
} catch (e) {
if (!!e && typeof e === "object" && "data" in e) {
return e;
}
if (e instanceof ActionError) {
return { error: e.toPlain() };
}
if (!!e && typeof e === "object" && "code" in e && "message" in e) {
return { error: { code: e.code, message: e.message } };
}
throw e;
}
}
}

export function createAction<T extends AnyFunc<ActionContext<any>>>(fn: T): ActionFunc<T> {
const action = new Action<T>(fn);

return new Proxy(fn as any, {
apply: (_target, _thisArg, argumentsList) => {
return action.run(...argumentsList);
},
});
}

export function actionError(code: string, message: string): never {
const e = new ActionError(code, message);
Error.captureStackTrace(e, actionError);
throw e;
}

export type { Action };

0 comments on commit 570b14e

Please sign in to comment.