@shivaedev/effect-react 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +25 -0
- package/dist/client/authAction.d.ts +15 -0
- package/dist/client/authAction.d.ts.map +1 -0
- package/dist/client/authAction.js +11 -0
- package/dist/client/authAction.js.map +1 -0
- package/package.json +6 -6
- package/src/client/authAction.ts +22 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.6.0 - 2026-10-18
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- `authAction` in `client/authAction.ts` binds Better Auth client promises to native action atoms for `useAction`, with pending state and typed returned failures. Rejected promises fail with the exported `AuthActionUnavailable` error; `AuthActionResult` describes the structural client result.
|
|
8
|
+
|
|
3
9
|
## 0.5.1 - 2026-10-18
|
|
4
10
|
|
|
5
11
|
### Fixed
|
package/README.md
CHANGED
|
@@ -141,6 +141,31 @@ create.dispatch({
|
|
|
141
141
|
|
|
142
142
|
An action's `dispatch(input)` returns `void`. Read the atom's latest result from `data`, `cause` or `result`. With the default `Atom.fn` action, a later dispatch interrupts the earlier work and the shared state reports the later result. Disable duplicate submissions or give independent work distinct native action atoms. When one caller needs its own success or failure, run the actual RPC Effect through its runtime, as the editor's `save` does; shared atom state cannot identify one invocation's completion.
|
|
143
143
|
|
|
144
|
+
### Better Auth actions
|
|
145
|
+
|
|
146
|
+
`authAction` from `@shivaedev/effect-react/client/authAction.ts` turns a Better Auth client call into a native action atom. Create it with the client, then pass it to `useAction` for the same `pending`, `data`, `cause`, `result` and `dispatch` shape as commands:
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
const signIn = authAction((credentials: { email: string; password: string }, signal) =>
|
|
150
|
+
authClient.signIn.email(credentials, { signal }),
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
function SignInButton({ email, password }: { email: string; password: string }) {
|
|
154
|
+
const action = useAction(signIn);
|
|
155
|
+
const failure = AsyncResult.error(action.result);
|
|
156
|
+
return (
|
|
157
|
+
<>
|
|
158
|
+
<button disabled={action.pending} onClick={() => action.dispatch({ email, password })}>
|
|
159
|
+
{action.pending ? "Signing in…" : "Sign in"}
|
|
160
|
+
</button>
|
|
161
|
+
{Option.isSome(failure) && <p role="alert">Sign-in failed</p>}
|
|
162
|
+
</>
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
The example uses `authAction`, `useAction`, `effect/reactivity/AsyncResult` and `effect/Option`, with an application-owned `authClient`. Returned auth errors keep their fields in the typed failure channel. Rejected promises become `AuthActionUnavailable` with the original rejection in `cause`. The application chooses error text and what happens after success.
|
|
168
|
+
|
|
144
169
|
### Route loaders with TanStack Router
|
|
145
170
|
|
|
146
171
|
TanStack Router owns routes, navigation, loader data and error components. `@shivaedev/effect-react/loadQuery.ts` supplies `loadQuery(registry, atom, loaderContext)` to read a contract query atom in the same registry as React. The atom runs through its native RPC runtime; the loader does not create another runtime or query cache.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as Atom from "effect/reactivity/Atom";
|
|
2
|
+
declare const AuthActionUnavailable_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
3
|
+
readonly _tag: "AuthActionUnavailable";
|
|
4
|
+
} & Readonly<A>;
|
|
5
|
+
export declare class AuthActionUnavailable extends AuthActionUnavailable_base<{
|
|
6
|
+
readonly cause: unknown;
|
|
7
|
+
}> {
|
|
8
|
+
}
|
|
9
|
+
export interface AuthActionResult<A, E> {
|
|
10
|
+
readonly data: A;
|
|
11
|
+
readonly error: E | null;
|
|
12
|
+
}
|
|
13
|
+
export declare function authAction<TInput, A, E extends object = never>(run: (input: TInput, signal: AbortSignal) => Promise<AuthActionResult<A, E>>): Atom.AtomResultFn<TInput, A, E | AuthActionUnavailable>;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=authAction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authAction.d.ts","sourceRoot":"","sources":["../../src/client/authAction.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,IAAI,MAAM,wBAAwB,CAAC;;;;AAE/C,qBAAa,qBAAsB,SAAQ,2BAA0C;IACpF,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACxB,CAAC;CAAG;AAEL,MAAM,WAAW,gBAAgB,CAAC,CAAC,EAAE,CAAC;IACrC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACjB,QAAQ,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;CACzB;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,SAAS,MAAM,GAAG,KAAK,EAC7D,GAAG,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAC1E,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,GAAG,qBAAqB,CAAC,CAOzD"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Data, Effect } from "effect";
|
|
2
|
+
import * as Atom from "effect/reactivity/Atom";
|
|
3
|
+
export class AuthActionUnavailable extends Data.TaggedError("AuthActionUnavailable") {
|
|
4
|
+
}
|
|
5
|
+
export function authAction(run) {
|
|
6
|
+
return Atom.fn()((input) => Effect.tryPromise({
|
|
7
|
+
catch: (cause) => new AuthActionUnavailable({ cause }),
|
|
8
|
+
try: (signal) => run(input, signal),
|
|
9
|
+
}).pipe(Effect.flatMap((result) => (result.error === null ? Effect.succeed(result.data) : Effect.fail(result.error)))));
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=authAction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authAction.js","sourceRoot":"","sources":["../../src/client/authAction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,IAAI,MAAM,wBAAwB,CAAC;AAE/C,MAAM,OAAO,qBAAsB,SAAQ,IAAI,CAAC,WAAW,CAAC,uBAAuB,CAEjF;CAAG;AAOL,MAAM,UAAU,UAAU,CACzB,GAA4E;IAE5E,OAAO,IAAI,CAAC,EAAE,EAAU,CAAC,CAAC,KAAK,EAAE,EAAE,CAClC,MAAM,CAAC,UAAU,CAAC;QACjB,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,qBAAqB,CAAC,EAAE,KAAK,EAAE,CAAC;QACtD,GAAG,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC;KACnC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CACtH,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shivaedev/effect-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "React query, action, editor and session hooks for native Effect atoms",
|
|
5
5
|
"homepage": "https://github.com/ShivaeDev/platform/tree/main/packages/effect-react#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -51,14 +51,14 @@
|
|
|
51
51
|
"@effect/platform-node": "4.0.4",
|
|
52
52
|
"@effect/sql-pg": "4.0.4",
|
|
53
53
|
"@effect/sql-sqlite-node": "4.0.4",
|
|
54
|
-
"@shivaedev/effect-pg-boss": "0.
|
|
54
|
+
"@shivaedev/effect-pg-boss": "0.10.0",
|
|
55
55
|
"@shivaedev/effect-service": "0.4.0",
|
|
56
56
|
"@shivaedev/effect-sql": "0.5.2",
|
|
57
57
|
"@shivaedev/effect-test": "0.6.0",
|
|
58
|
-
"@shivaedev/local-postgres": "0.4.
|
|
59
|
-
"@shivaedev/platform": "0.
|
|
60
|
-
"@shivaedev/quality": "0.
|
|
61
|
-
"@shivaedev/test-story": "0.
|
|
58
|
+
"@shivaedev/local-postgres": "0.4.1",
|
|
59
|
+
"@shivaedev/platform": "0.17.0",
|
|
60
|
+
"@shivaedev/quality": "0.27.0",
|
|
61
|
+
"@shivaedev/test-story": "0.9.0",
|
|
62
62
|
"@tanstack/react-router": "1.170.42",
|
|
63
63
|
"@types/node": "24.19.2",
|
|
64
64
|
"@types/react": "19.3.0",
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Data, Effect } from "effect";
|
|
2
|
+
import * as Atom from "effect/reactivity/Atom";
|
|
3
|
+
|
|
4
|
+
export class AuthActionUnavailable extends Data.TaggedError("AuthActionUnavailable")<{
|
|
5
|
+
readonly cause: unknown;
|
|
6
|
+
}> {}
|
|
7
|
+
|
|
8
|
+
export interface AuthActionResult<A, E> {
|
|
9
|
+
readonly data: A;
|
|
10
|
+
readonly error: E | null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function authAction<TInput, A, E extends object = never>(
|
|
14
|
+
run: (input: TInput, signal: AbortSignal) => Promise<AuthActionResult<A, E>>,
|
|
15
|
+
): Atom.AtomResultFn<TInput, A, E | AuthActionUnavailable> {
|
|
16
|
+
return Atom.fn<TInput>()((input) =>
|
|
17
|
+
Effect.tryPromise({
|
|
18
|
+
catch: (cause) => new AuthActionUnavailable({ cause }),
|
|
19
|
+
try: (signal) => run(input, signal),
|
|
20
|
+
}).pipe(Effect.flatMap((result) => (result.error === null ? Effect.succeed(result.data) : Effect.fail(result.error)))),
|
|
21
|
+
);
|
|
22
|
+
}
|