oxidejs 0.2.4 → 0.3.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.
@@ -0,0 +1,64 @@
1
+ import * as Atom from "effect/unstable/reactivity/Atom";
2
+ import * as AsyncResult from "effect/unstable/reactivity/AsyncResult";
3
+ //#region src/action.d.ts
4
+ declare const ACTION_CALL: unique symbol;
5
+ type CallOptions = {
6
+ signal?: AbortSignal;
7
+ };
8
+ type ServerActionHandle<Args extends unknown[], A> = {
9
+ (...args: Args | [...Args, CallOptions]): Promise<A>;
10
+ set(...args: Args): Promise<A>;
11
+ bind(...args: Args): (...ev: unknown[]) => void;
12
+ with(...args: Args): (...ev: unknown[]) => void;
13
+ /** Last `AsyncResult` for this action's client atom (does not invoke RPC). */
14
+ readonly result: AsyncResult.AsyncResult<A, unknown>;
15
+ readonly atom: Atom.Atom<unknown>;
16
+ readonly $$atom: 1;
17
+ };
18
+ type StreamActionHandle<Args extends unknown[], Y, R = void> = {
19
+ (...args: Args | [...Args, CallOptions]): AsyncGenerator<Y, R, undefined>;
20
+ set(...args: Args): AsyncGenerator<Y, R, undefined>;
21
+ bind(...args: Args): (...ev: unknown[]) => void;
22
+ with(...args: Args): (...ev: unknown[]) => void;
23
+ readonly atom: undefined;
24
+ readonly $$atom: 1;
25
+ };
26
+ /** Attach an ilha server-island capture key to an action handle. */
27
+ declare function brandServerAction<Args extends unknown[], A>(key: string, handle: ServerActionHandle<Args, A>): ServerActionHandle<Args, A>;
28
+ /** Wrap an RPC caller as an `Atom.fn`-shaped client action handle. */
29
+ declare function wrapClientRpc<Args extends unknown[], A>(rpc: (...args: Args | [...Args, CallOptions]) => Promise<A>): ServerActionHandle<Args, A>;
30
+ /**
31
+ * Wrap a streaming RPC caller so the client handle returns an async generator
32
+ * (awaiting the underlying client lazily), not `Promise<AsyncGenerator>`.
33
+ */
34
+ declare function wrapClientStreamRpc<Args extends unknown[], Y, R = void>(rpc: (...args: Args | [...Args, CallOptions]) => AsyncGenerator<Y, R, undefined>): StreamActionHandle<Args, Y, R>;
35
+ /**
36
+ * Marks a `*.server.ts` export as a remote RPC action. On the server the
37
+ * underlying function runs locally; on the client the build replaces the module
38
+ * with an `Atom.fn`-shaped RPC handle (`set`, `bind`, `result`).
39
+ */
40
+ declare function action<Args extends unknown[], Y, R = void>(fn: (...args: Args) => AsyncGenerator<Y, R, unknown>): StreamActionHandle<Args, Y, R>;
41
+ declare function action<Args extends unknown[], Result>(fn: (...args: Args) => Result): ServerActionHandle<Args, Awaited<Result>>;
42
+ //#endregion
43
+ //#region src/context.d.ts
44
+ type ExecutionContext = {
45
+ waitUntil?(promise: Promise<unknown>): void;
46
+ passThroughOnException?(): void;
47
+ };
48
+ /** RPC procedure request context. Starts as `{ req }` plus Worker extras. Middleware can add fields. */
49
+ type ActionContext = {
50
+ req: Request;
51
+ env?: unknown;
52
+ fetchCtx?: ExecutionContext;
53
+ [key: string]: unknown;
54
+ };
55
+ /** Current RPC or host request context. Throws outside request handling. */
56
+ declare function useCtx<C extends ActionContext = ActionContext>(): C;
57
+ /** Current server `Request`. Available in actions, SSR, and frame renders. */
58
+ declare function useRequest(): Request;
59
+ /** Worker `env` from `fetch(request, env, ctx)`. `undefined` on the Node fetch preset. */
60
+ declare function useEnv<E = unknown>(): E | undefined;
61
+ /** Worker `ctx` from `fetch(request, env, ctx)` (`waitUntil`). `undefined` on Node. */
62
+ declare function useFetchCtx(): ExecutionContext | undefined;
63
+ //#endregion
64
+ export { useFetchCtx as a, ServerActionHandle as c, brandServerAction as d, wrapClientRpc as f, useEnv as i, StreamActionHandle as l, ExecutionContext as n, useRequest as o, wrapClientStreamRpc as p, useCtx as r, ACTION_CALL as s, ActionContext as t, action as u };
@@ -0,0 +1,42 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ //#region src/context.ts
3
+ const ALS_KEY = Symbol.for("oxidejs.requestContext");
4
+ const FETCH_KEY = Symbol.for("oxidejs.fetch");
5
+ function als() {
6
+ const g = globalThis;
7
+ return g[ALS_KEY] ??= new AsyncLocalStorage();
8
+ }
9
+ function store() {
10
+ const current = als().getStore();
11
+ if (!current) throw new Error("oxidejs: request context is unavailable");
12
+ return current;
13
+ }
14
+ /** Current RPC or host request context. Throws outside request handling. */
15
+ function useCtx() {
16
+ return store();
17
+ }
18
+ /** Current server `Request`. Available in actions, SSR, and frame renders. */
19
+ function useRequest() {
20
+ return store().req;
21
+ }
22
+ /** Worker `env` from `fetch(request, env, ctx)`. `undefined` on the Node fetch preset. */
23
+ function useEnv() {
24
+ return store().env;
25
+ }
26
+ /** Worker `ctx` from `fetch(request, env, ctx)` (`waitUntil`). `undefined` on Node. */
27
+ function useFetchCtx() {
28
+ return store().fetchCtx;
29
+ }
30
+ function runWithRequest(req, fn, extra) {
31
+ return als().run({
32
+ ...extra,
33
+ req
34
+ }, fn);
35
+ }
36
+ const HOOK_KEY = Symbol.for("oxidejs.runWithRequest");
37
+ globalThis[HOOK_KEY] ??= (req, fn) => {
38
+ const extra = req[FETCH_KEY];
39
+ return runWithRequest(req, fn, extra);
40
+ };
41
+ //#endregion
42
+ export { useRequest as a, useFetchCtx as i, useCtx as n, useEnv as r, runWithRequest as t };
package/dist/index.d.mts CHANGED
@@ -1,30 +1,3 @@
1
+ import { a as useFetchCtx, c as ServerActionHandle, d as brandServerAction, f as wrapClientRpc, i as useEnv, l as StreamActionHandle, n as ExecutionContext, o as useRequest, p as wrapClientStreamRpc, r as useCtx, s as ACTION_CALL, t as ActionContext, u as action } from "./context-C1UFQ0Zc.mjs";
1
2
  import { a as OxidejsWranglerOptions, i as OxidejsPreset, n as OxidejsActionTransport, o as ResolvedOptions, r as OxidejsOptions, t as OxidejsActionHeaders } from "./types-BM4NAnzy.mjs";
2
- //#region src/context.d.ts
3
- type ExecutionContext = {
4
- waitUntil?(promise: Promise<unknown>): void;
5
- passThroughOnException?(): void;
6
- };
7
- /** Tacho procedure `ctx`. Starts as `{ req }` plus Worker extras. Middleware can add fields. */
8
- type ActionContext = {
9
- req: Request;
10
- env?: unknown;
11
- fetchCtx?: ExecutionContext;
12
- [key: string]: unknown;
13
- };
14
- /** Current tacho or host request context. Throws outside request handling. */
15
- declare function useCtx<C extends ActionContext = ActionContext>(): C;
16
- /** Current server `Request`. Available in actions, SSR, and frame renders. */
17
- declare function useRequest(): Request;
18
- /** Worker `env` from `fetch(request, env, ctx)`. `undefined` on the Node fetch preset. */
19
- declare function useEnv<E = unknown>(): E | undefined;
20
- /** Worker `ctx` from `fetch(request, env, ctx)` (`waitUntil`). Not tacho `ctx`. `undefined` on Node. */
21
- declare function useFetchCtx(): ExecutionContext | undefined;
22
- /**
23
- * Marks a `*.server.ts` export as a remote RPC action. Runtime identity; the
24
- * second call signature adds the transport-only `{ signal }` argument.
25
- */
26
- declare function action<Args extends unknown[], Result>(fn: (...args: Args) => Result): typeof fn & ((...args: [...Args, options: {
27
- signal?: AbortSignal;
28
- }]) => Result);
29
- //#endregion
30
- export { type ActionContext, type ExecutionContext, type OxidejsActionHeaders, type OxidejsActionTransport, type OxidejsOptions, type OxidejsPreset, type OxidejsWranglerOptions, type ResolvedOptions, action, useCtx, useEnv, useFetchCtx, useRequest };
3
+ export { ACTION_CALL, type ActionContext, type ExecutionContext, type OxidejsActionHeaders, type OxidejsActionTransport, type OxidejsOptions, type OxidejsPreset, type OxidejsWranglerOptions, type ResolvedOptions, type ServerActionHandle, type StreamActionHandle, action, brandServerAction, useCtx, useEnv, useFetchCtx, useRequest, wrapClientRpc, wrapClientStreamRpc };
package/dist/index.mjs CHANGED
@@ -1,49 +1,108 @@
1
- import { AsyncLocalStorage } from "node:async_hooks";
2
- //#region src/context.ts
3
- const ALS_KEY = Symbol.for("oxidejs.requestContext");
4
- const FETCH_KEY = Symbol.for("oxidejs.fetch");
5
- function als() {
6
- const g = globalThis;
7
- return g[ALS_KEY] ??= new AsyncLocalStorage();
8
- }
9
- function store() {
10
- const current = als().getStore();
11
- if (!current) throw new Error("oxidejs: request context is unavailable");
12
- return current;
13
- }
14
- /** Current tacho or host request context. Throws outside request handling. */
15
- function useCtx() {
16
- return store();
17
- }
18
- /** Current server `Request`. Available in actions, SSR, and frame renders. */
19
- function useRequest() {
20
- return store().req;
21
- }
22
- /** Worker `env` from `fetch(request, env, ctx)`. `undefined` on the Node fetch preset. */
23
- function useEnv() {
24
- return store().env;
25
- }
26
- /** Worker `ctx` from `fetch(request, env, ctx)` (`waitUntil`). Not tacho `ctx`. `undefined` on Node. */
27
- function useFetchCtx() {
28
- return store().fetchCtx;
29
- }
30
- function runWithRequest(req, fn, extra) {
31
- return als().run({
32
- ...extra,
33
- req
34
- }, fn);
35
- }
36
- const HOOK_KEY = Symbol.for("oxidejs.runWithRequest");
37
- globalThis[HOOK_KEY] ??= (req, fn) => {
38
- const extra = req[FETCH_KEY];
39
- return runWithRequest(req, fn, extra);
40
- };
1
+ import { a as useRequest, i as useFetchCtx, n as useCtx, r as useEnv } from "./context-zrTZyYpF.mjs";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Atom from "effect/unstable/reactivity/Atom";
4
+ import * as Registry from "effect/unstable/reactivity/AtomRegistry";
5
+ //#region src/action.ts
6
+ const ACTION_CALL = Symbol.for("ilha.actionCall");
7
+ const ACTION_KEY = Symbol.for("oxidejs.actionKey");
8
+ const AsyncGeneratorFunction = Object.getPrototypeOf(async function* () {}).constructor;
9
+ let defaultRegistry;
10
+ function registry() {
11
+ return defaultRegistry ??= Registry.make();
12
+ }
13
+ function isAsyncGeneratorFunction(fn) {
14
+ return typeof fn === "function" && fn instanceof AsyncGeneratorFunction;
15
+ }
16
+ function splitCallOptions(args) {
17
+ if (args.length === 0) return { args: [] };
18
+ const last = args[args.length - 1];
19
+ if (last && typeof last === "object" && "signal" in last && last.signal instanceof AbortSignal && Object.keys(last).length === 1) return {
20
+ args: args.slice(0, -1),
21
+ options: last
22
+ };
23
+ return { args };
24
+ }
25
+ function bindHandler(key, invoke, args) {
26
+ const handler = ((..._ev) => invoke(...args));
27
+ if (key) handler[ACTION_CALL] = {
28
+ k: key,
29
+ a: args
30
+ };
31
+ return handler;
32
+ }
33
+ function defineServerAction(atom, invoke, opts) {
34
+ const captureKey = opts?.captureKey;
35
+ const stripCallOptions = opts?.stripCallOptions ?? true;
36
+ const run = ((...allArgs) => {
37
+ if (!stripCallOptions) return Promise.resolve(invoke(...allArgs));
38
+ const { args } = splitCallOptions(allArgs);
39
+ return Promise.resolve(invoke(...args));
40
+ });
41
+ const set = (...args) => {
42
+ registry().set(atom, args);
43
+ return Promise.resolve(invoke(...args));
44
+ };
45
+ const bind = (...args) => {
46
+ return bindHandler(captureKey ?? run[ACTION_KEY], (...a) => void set(...a), args);
47
+ };
48
+ Object.assign(run, {
49
+ set,
50
+ bind,
51
+ with: bind,
52
+ atom,
53
+ $$atom: 1
54
+ });
55
+ Object.defineProperty(run, "result", {
56
+ enumerable: true,
57
+ get: () => registry().get(atom)
58
+ });
59
+ if (captureKey) run[ACTION_KEY] = captureKey;
60
+ return run;
61
+ }
62
+ function defineStreamAction(fn) {
63
+ const call = ((...allArgs) => {
64
+ const { args } = splitCallOptions(allArgs);
65
+ return fn(...args);
66
+ });
67
+ const deny = () => {
68
+ throw new Error("oxidejs: stream actions cannot be bound to DOM events");
69
+ };
70
+ Object.assign(call, {
71
+ set: call,
72
+ bind: deny,
73
+ with: deny,
74
+ atom: void 0,
75
+ $$atom: 1
76
+ });
77
+ return call;
78
+ }
79
+ /** Attach an ilha server-island capture key to an action handle. */
80
+ function brandServerAction(key, handle) {
81
+ handle[ACTION_KEY] = key;
82
+ return handle;
83
+ }
84
+ /** Wrap an RPC caller as an `Atom.fn`-shaped client action handle. */
85
+ function wrapClientRpc(rpc) {
86
+ const invoke = (...args) => Promise.resolve(rpc(...args));
87
+ return defineServerAction(Atom.make(Atom.fn((packed) => Effect.tryPromise({
88
+ try: () => invoke(...packed),
89
+ catch: (error) => error instanceof Error ? error : new Error(String(error))
90
+ }))), (...args) => invoke(...args), { stripCallOptions: false });
91
+ }
41
92
  /**
42
- * Marks a `*.server.ts` export as a remote RPC action. Runtime identity; the
43
- * second call signature adds the transport-only `{ signal }` argument.
93
+ * Wrap a streaming RPC caller so the client handle returns an async generator
94
+ * (awaiting the underlying client lazily), not `Promise<AsyncGenerator>`.
44
95
  */
96
+ function wrapClientStreamRpc(rpc) {
97
+ return defineStreamAction((...args) => rpc(...args));
98
+ }
45
99
  function action(fn) {
46
- return fn;
100
+ if (isAsyncGeneratorFunction(fn)) return defineStreamAction(fn);
101
+ const invoke = (...args) => Promise.resolve(fn(...args));
102
+ return defineServerAction(Atom.make(Atom.fn((packed) => Effect.tryPromise({
103
+ try: () => invoke(...packed),
104
+ catch: (error) => error instanceof Error ? error : new Error(String(error))
105
+ }))), invoke);
47
106
  }
48
107
  //#endregion
49
- export { action, useCtx, useEnv, useFetchCtx, useRequest };
108
+ export { ACTION_CALL, action, brandServerAction, useCtx, useEnv, useFetchCtx, useRequest, wrapClientRpc, wrapClientStreamRpc };