oxidejs 0.3.1 → 0.3.2
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/README.md +1 -0
- package/dist/{client-C-s6XXpS.mjs → client-BgBfkZDx.mjs} +24 -6
- package/dist/{context-C1UFQ0Zc.d.mts → context-Ct8u5XUC.d.mts} +10 -1
- package/dist/context-DQDDwFYi.mjs +100 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/{plugin-HZKRDuCS.mjs → plugin-CurpVnGn.mjs} +2 -2
- package/dist/plugin.mjs +1 -1
- package/dist/rpc/client.mjs +1 -1
- package/dist/{rpc-DzUkWWgQ.mjs → rpc-tYqxQToi.mjs} +26 -29
- package/dist/rpc.d.mts +6 -3
- package/dist/rpc.mjs +2 -2
- package/dist/rsbuild.mjs +1 -1
- package/dist/vite.mjs +1 -1
- package/package.json +1 -1
- package/dist/context-zrTZyYpF.mjs +0 -42
package/README.md
CHANGED
|
@@ -201,6 +201,7 @@ The generated `__asset` function uses `path.join` — not `path.resolve` — so
|
|
|
201
201
|
- Batch requests capped at 20 items (both HTTP and WebSocket transports).
|
|
202
202
|
- Effect `Defect` / `Cause` payloads are scrubbed before they leave the endpoint. Clients see plain JSON-RPC errors (`code` + `message` only). Thrown messages become `Internal error` (`-32603`). Unknown methods → `-32601`; invalid params → `-32602`.
|
|
203
203
|
- `actions.sameOrigin` defaults to `true`. Requests without both `Origin` and `Sec-Fetch-Site` are rejected when that check is on.
|
|
204
|
+
- StackBlitz WebContainers do not keep `AsyncLocalStorage` across `async/await`. Oxide detects `process.versions.webcontainer` and falls back to a sync request store, capturing context before Effect schedules work and serializing handler entry so concurrent requests do not stomp that store. Stream pulls re-enter the captured store. This is a demo/dev workaround, not a concurrency model for production.
|
|
204
205
|
|
|
205
206
|
### Host header
|
|
206
207
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { n as inWebcontainer } from "./context-DQDDwFYi.mjs";
|
|
1
2
|
import { Effect, Layer, Scope, Stream } from "effect";
|
|
2
3
|
import { RpcClient, RpcSchema, RpcSerialization } from "effect/unstable/rpc";
|
|
3
4
|
import { FetchHttpClient, HttpClient, HttpClientRequest } from "effect/unstable/http";
|
|
@@ -6,20 +7,37 @@ import { Socket } from "effect/unstable/socket";
|
|
|
6
7
|
function asyncGenToStream(gen) {
|
|
7
8
|
return Stream.fromAsyncIterable(gen, (error) => error instanceof Error ? error : new Error(String(error)));
|
|
8
9
|
}
|
|
10
|
+
/** Serialize WebContainer stream pulls so the shared syncStore is not stomped. */
|
|
11
|
+
let pullTail = Promise.resolve();
|
|
9
12
|
/**
|
|
10
|
-
* Re-enter `run` for every generator pull so
|
|
11
|
-
*
|
|
13
|
+
* Re-enter `run` for every generator pull so request context stays available
|
|
14
|
+
* across yields (Effect may drain the stream after the outer ALS scope ends;
|
|
15
|
+
* WebContainer also loses ALS across awaits, so `run` must reinstall the store).
|
|
16
|
+
* On WebContainer, pulls are serialized through settlement so concurrent streams
|
|
17
|
+
* cannot replace the sync fallback mid-pull. `withRequestEntry` is unchanged.
|
|
12
18
|
*/
|
|
13
19
|
function bindAsyncGenContext(gen, run) {
|
|
20
|
+
const runPull = (fn) => {
|
|
21
|
+
if (!inWebcontainer()) return run(fn);
|
|
22
|
+
let release;
|
|
23
|
+
const gate = new Promise((resolve) => {
|
|
24
|
+
release = resolve;
|
|
25
|
+
});
|
|
26
|
+
const prev = pullTail;
|
|
27
|
+
pullTail = gate;
|
|
28
|
+
return prev.then(() => Promise.resolve(run(fn))).finally(() => {
|
|
29
|
+
release();
|
|
30
|
+
});
|
|
31
|
+
};
|
|
14
32
|
return {
|
|
15
|
-
next: (value) =>
|
|
16
|
-
return: (value) =>
|
|
17
|
-
throw: (error) =>
|
|
33
|
+
next: (value) => runPull(() => gen.next(value)),
|
|
34
|
+
return: (value) => runPull(() => gen.return(value)),
|
|
35
|
+
throw: (error) => runPull(() => gen.throw(error)),
|
|
18
36
|
[Symbol.asyncIterator]() {
|
|
19
37
|
return this;
|
|
20
38
|
},
|
|
21
39
|
async [Symbol.asyncDispose]() {
|
|
22
|
-
await
|
|
40
|
+
await runPull(() => gen.return(void 0));
|
|
23
41
|
}
|
|
24
42
|
};
|
|
25
43
|
}
|
|
@@ -52,6 +52,15 @@ type ActionContext = {
|
|
|
52
52
|
fetchCtx?: ExecutionContext;
|
|
53
53
|
[key: string]: unknown;
|
|
54
54
|
};
|
|
55
|
+
/** Current request context: ALS first, then the WebContainer sync fallback. */
|
|
56
|
+
declare function getRequestStore(): ActionContext;
|
|
57
|
+
/**
|
|
58
|
+
* Run `fn` with `store` on ALS and the sync fallback. On WebContainer the sync
|
|
59
|
+
* slot is restored only after an async `fn` settles (streams capture the store
|
|
60
|
+
* at invoke time and re-enter via this helper on each pull). Sync returns and
|
|
61
|
+
* throws restore immediately so a completed request is not left visible.
|
|
62
|
+
*/
|
|
63
|
+
declare function withRequestStore<T>(ctx: ActionContext, fn: () => T): T;
|
|
55
64
|
/** Current RPC or host request context. Throws outside request handling. */
|
|
56
65
|
declare function useCtx<C extends ActionContext = ActionContext>(): C;
|
|
57
66
|
/** Current server `Request`. Available in actions, SSR, and frame renders. */
|
|
@@ -61,4 +70,4 @@ declare function useEnv<E = unknown>(): E | undefined;
|
|
|
61
70
|
/** Worker `ctx` from `fetch(request, env, ctx)` (`waitUntil`). `undefined` on Node. */
|
|
62
71
|
declare function useFetchCtx(): ExecutionContext | undefined;
|
|
63
72
|
//#endregion
|
|
64
|
-
export {
|
|
73
|
+
export { useEnv as a, withRequestStore as c, StreamActionHandle as d, action as f, wrapClientStreamRpc as h, useCtx as i, ACTION_CALL as l, wrapClientRpc as m, ExecutionContext as n, useFetchCtx as o, brandServerAction as p, getRequestStore as r, useRequest as s, ActionContext as t, ServerActionHandle as u };
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
//#region src/context.ts
|
|
4
|
+
const ALS_KEY = Symbol.for("oxidejs.requestContext");
|
|
5
|
+
const FETCH_KEY = Symbol.for("oxidejs.fetch");
|
|
6
|
+
/** StackBlitz WebContainers lose AsyncLocalStorage across `async/await`. */
|
|
7
|
+
const inWebcontainer = () => {
|
|
8
|
+
if (typeof process === "undefined") return false;
|
|
9
|
+
const versions = process.versions;
|
|
10
|
+
return Boolean(versions.webcontainer);
|
|
11
|
+
};
|
|
12
|
+
/** Module fallback when ALS does not survive awaits (WebContainer). */
|
|
13
|
+
let syncStore = null;
|
|
14
|
+
/** Serialize handler *entry* on WebContainer so syncStore is not stomped. */
|
|
15
|
+
let entryTail = Promise.resolve();
|
|
16
|
+
function als() {
|
|
17
|
+
const g = globalThis;
|
|
18
|
+
return g[ALS_KEY] ??= new AsyncLocalStorage();
|
|
19
|
+
}
|
|
20
|
+
const isPromiseLike = (value) => value !== null && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
|
|
21
|
+
/** Current request context: ALS first, then the WebContainer sync fallback. */
|
|
22
|
+
function getRequestStore() {
|
|
23
|
+
const current = als().getStore() ?? syncStore;
|
|
24
|
+
if (!current) throw new Error("oxidejs: request context is unavailable");
|
|
25
|
+
return current;
|
|
26
|
+
}
|
|
27
|
+
function store() {
|
|
28
|
+
return getRequestStore();
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Run `fn` with `store` on ALS and the sync fallback. On WebContainer the sync
|
|
32
|
+
* slot is restored only after an async `fn` settles (streams capture the store
|
|
33
|
+
* at invoke time and re-enter via this helper on each pull). Sync returns and
|
|
34
|
+
* throws restore immediately so a completed request is not left visible.
|
|
35
|
+
*/
|
|
36
|
+
function withRequestStore(ctx, fn) {
|
|
37
|
+
const previous = syncStore;
|
|
38
|
+
syncStore = ctx;
|
|
39
|
+
let deferRestore = false;
|
|
40
|
+
try {
|
|
41
|
+
const result = als().run(ctx, fn);
|
|
42
|
+
if (inWebcontainer() && isPromiseLike(result)) {
|
|
43
|
+
deferRestore = true;
|
|
44
|
+
return Promise.resolve(result).finally(() => {
|
|
45
|
+
if (syncStore === ctx) syncStore = previous;
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
} finally {
|
|
50
|
+
if (!deferRestore) syncStore = previous;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Serialize async work that installs request context on WebContainer.
|
|
55
|
+
* Release as soon as `fn` settles — do not wait for streamed response bodies.
|
|
56
|
+
*/
|
|
57
|
+
async function withRequestEntry(fn) {
|
|
58
|
+
if (!inWebcontainer()) return fn();
|
|
59
|
+
let release;
|
|
60
|
+
const gate = new Promise((resolve) => {
|
|
61
|
+
release = resolve;
|
|
62
|
+
});
|
|
63
|
+
const previous = entryTail;
|
|
64
|
+
entryTail = gate;
|
|
65
|
+
await previous;
|
|
66
|
+
try {
|
|
67
|
+
return await fn();
|
|
68
|
+
} finally {
|
|
69
|
+
release();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/** Current RPC or host request context. Throws outside request handling. */
|
|
73
|
+
function useCtx() {
|
|
74
|
+
return store();
|
|
75
|
+
}
|
|
76
|
+
/** Current server `Request`. Available in actions, SSR, and frame renders. */
|
|
77
|
+
function useRequest() {
|
|
78
|
+
return store().req;
|
|
79
|
+
}
|
|
80
|
+
/** Worker `env` from `fetch(request, env, ctx)`. `undefined` on the Node fetch preset. */
|
|
81
|
+
function useEnv() {
|
|
82
|
+
return store().env;
|
|
83
|
+
}
|
|
84
|
+
/** Worker `ctx` from `fetch(request, env, ctx)` (`waitUntil`). `undefined` on Node. */
|
|
85
|
+
function useFetchCtx() {
|
|
86
|
+
return store().fetchCtx;
|
|
87
|
+
}
|
|
88
|
+
function runWithRequest(req, fn, extra) {
|
|
89
|
+
return withRequestStore({
|
|
90
|
+
...extra,
|
|
91
|
+
req
|
|
92
|
+
}, fn);
|
|
93
|
+
}
|
|
94
|
+
const HOOK_KEY = Symbol.for("oxidejs.runWithRequest");
|
|
95
|
+
globalThis[HOOK_KEY] ??= (req, fn) => {
|
|
96
|
+
const extra = req[FETCH_KEY];
|
|
97
|
+
return runWithRequest(req, fn, extra);
|
|
98
|
+
};
|
|
99
|
+
//#endregion
|
|
100
|
+
export { useEnv as a, withRequestEntry as c, useCtx as i, withRequestStore as l, inWebcontainer as n, useFetchCtx as o, runWithRequest as r, useRequest as s, getRequestStore as t };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as useEnv, c as withRequestStore, d as StreamActionHandle, f as action, h as wrapClientStreamRpc, i as useCtx, l as ACTION_CALL, m as wrapClientRpc, n as ExecutionContext, o as useFetchCtx, p as brandServerAction, r as getRequestStore, s as useRequest, t as ActionContext, u as ServerActionHandle } from "./context-Ct8u5XUC.mjs";
|
|
2
2
|
import { a as OxidejsWranglerOptions, i as OxidejsPreset, n as OxidejsActionTransport, o as ResolvedOptions, r as OxidejsOptions, t as OxidejsActionHeaders } from "./types-BM4NAnzy.mjs";
|
|
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 };
|
|
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, getRequestStore, useCtx, useEnv, useFetchCtx, useRequest, withRequestStore, wrapClientRpc, wrapClientStreamRpc };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as useEnv, i as useCtx, l as withRequestStore, o as useFetchCtx, s as useRequest, t as getRequestStore } from "./context-DQDDwFYi.mjs";
|
|
2
2
|
import * as Effect from "effect/Effect";
|
|
3
3
|
import * as Atom from "effect/unstable/reactivity/Atom";
|
|
4
4
|
import * as Registry from "effect/unstable/reactivity/AtomRegistry";
|
|
@@ -105,4 +105,4 @@ function action(fn) {
|
|
|
105
105
|
}))), invoke);
|
|
106
106
|
}
|
|
107
107
|
//#endregion
|
|
108
|
-
export { ACTION_CALL, action, brandServerAction, useCtx, useEnv, useFetchCtx, useRequest, wrapClientRpc, wrapClientStreamRpc };
|
|
108
|
+
export { ACTION_CALL, action, brandServerAction, getRequestStore, useCtx, useEnv, useFetchCtx, useRequest, withRequestStore, wrapClientRpc, wrapClientStreamRpc };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as pluginShouldStub, C as isServerFileId, D as nodeToWebRequest, E as moduleKey, M as sendWebResponseFrom, O as parseExportedNames, S as generateWorkerWrapper, T as matchesActionPath, b as generateClientModule, d as RESOLVED_VIRTUAL_CLIENT_ID, f as RESOLVED_VIRTUAL_WORKER_ID, g as VIRTUAL_WORKER_ID, j as scanServerFiles, k as parseStreamExports, l as ACTION_PATH, m as VIRTUAL_ACTIONS_ID, n as createActionHandler, p as RequestBodyTooLargeError, t as createWsHooks, u as RESOLVED_VIRTUAL_ACTIONS_ID, v as generateActionsClientModule, w as loadClientStub, x as generateClientStub, y as generateActionsModule } from "./rpc-
|
|
1
|
+
import { A as pluginShouldStub, C as isServerFileId, D as nodeToWebRequest, E as moduleKey, M as sendWebResponseFrom, O as parseExportedNames, S as generateWorkerWrapper, T as matchesActionPath, b as generateClientModule, d as RESOLVED_VIRTUAL_CLIENT_ID, f as RESOLVED_VIRTUAL_WORKER_ID, g as VIRTUAL_WORKER_ID, j as scanServerFiles, k as parseStreamExports, l as ACTION_PATH, m as VIRTUAL_ACTIONS_ID, n as createActionHandler, p as RequestBodyTooLargeError, t as createWsHooks, u as RESOLVED_VIRTUAL_ACTIONS_ID, v as generateActionsClientModule, w as loadClientStub, x as generateClientStub, y as generateActionsModule } from "./rpc-tYqxQToi.mjs";
|
|
2
2
|
import { ensureWorkerDom } from "./worker-dom.mjs";
|
|
3
3
|
import { createUnplugin } from "unplugin";
|
|
4
4
|
import fs from "node:fs";
|
|
@@ -531,7 +531,7 @@ const unpluginFactory = (options) => {
|
|
|
531
531
|
next();
|
|
532
532
|
return;
|
|
533
533
|
}
|
|
534
|
-
const { nodeToWebRequest, sendWebResponseFrom } = await import("./rpc-
|
|
534
|
+
const { nodeToWebRequest, sendWebResponseFrom } = await import("./rpc-tYqxQToi.mjs").then((n) => n._);
|
|
535
535
|
const request = await nodeToWebRequest(creq, resolved.bodyLimit);
|
|
536
536
|
const context = {
|
|
537
537
|
env: resolved.env,
|
package/dist/plugin.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as unpluginFactory, r as vite, t as oxidejs } from "./plugin-
|
|
1
|
+
import { n as unpluginFactory, r as vite, t as oxidejs } from "./plugin-CurpVnGn.mjs";
|
|
2
2
|
export { oxidejs as default, oxidejs, unpluginFactory, vite };
|
package/dist/rpc/client.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as createClient } from "../client-
|
|
1
|
+
import { t as createClient } from "../client-BgBfkZDx.mjs";
|
|
2
2
|
export { createClient };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { c as withRequestEntry, r as runWithRequest } from "./context-DQDDwFYi.mjs";
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { Layer } from "effect";
|
|
@@ -188,17 +188,11 @@ function generateActionsModule(modules, opts) {
|
|
|
188
188
|
`import { Effect } from "effect";`,
|
|
189
189
|
`import { Schema } from "effect";`,
|
|
190
190
|
`import { Rpc, RpcGroup } from "effect/unstable/rpc";`,
|
|
191
|
-
`import {
|
|
191
|
+
`import { getRequestStore, withRequestStore } from "oxidejs";`,
|
|
192
192
|
`import { asyncGenToStreamInContext } from "oxidejs/rpc";`,
|
|
193
|
-
`const
|
|
194
|
-
`const
|
|
195
|
-
`
|
|
196
|
-
` const ctx = __als.getStore();`,
|
|
197
|
-
` if (!ctx) throw new Error("oxidejs: request context is unavailable");`,
|
|
198
|
-
` return ctx;`,
|
|
199
|
-
`};`,
|
|
200
|
-
`const __run = (fn) =>`,
|
|
201
|
-
` Effect.promise(() => __als.run(__store(), fn)).pipe(`,
|
|
193
|
+
`const __run = (fn) => {`,
|
|
194
|
+
` const __s = getRequestStore();`,
|
|
195
|
+
` return Effect.promise(() => withRequestStore(__s, fn)).pipe(`,
|
|
202
196
|
` Effect.map((value) => {`,
|
|
203
197
|
` if (value instanceof Response) {`,
|
|
204
198
|
` console.error("oxidejs: action() returned a Response; actions must return serializable data. Return a Response from src/server.ts for raw HTTP responses.");`,
|
|
@@ -207,7 +201,8 @@ function generateActionsModule(modules, opts) {
|
|
|
207
201
|
` return value === undefined ? null : value;`,
|
|
208
202
|
` }),`,
|
|
209
203
|
` );`,
|
|
210
|
-
`
|
|
204
|
+
`};`,
|
|
205
|
+
`const __withStore = (store, fn) => withRequestStore(store, fn);`
|
|
211
206
|
];
|
|
212
207
|
const rpcNames = [];
|
|
213
208
|
const aliases = modules.map((mod, i) => {
|
|
@@ -231,7 +226,7 @@ function generateActionsModule(modules, opts) {
|
|
|
231
226
|
for (const { alias, mod } of aliases) for (const name of mod.exports) {
|
|
232
227
|
const tag = `${mod.key}.${name}`;
|
|
233
228
|
const stream = mod.streams?.includes(name) ?? false;
|
|
234
|
-
lines.push(stream ? ` ${JSON.stringify(tag)}: ({ args }) => { const __s =
|
|
229
|
+
lines.push(stream ? ` ${JSON.stringify(tag)}: ({ args }) => { const __s = getRequestStore(); return asyncGenToStreamInContext(() => ${alias}[${JSON.stringify(name)}].apply(null, args), (fn) => __withStore(__s, fn)); },` : ` ${JSON.stringify(tag)}: ({ args }) => __run(() => ${alias}[${JSON.stringify(name)}].apply(null, args)),`);
|
|
235
230
|
}
|
|
236
231
|
lines.push(`});`);
|
|
237
232
|
lines.push(`export default actionsGroup;`);
|
|
@@ -757,23 +752,25 @@ function createActionHandler(group, handlers, options = {}) {
|
|
|
757
752
|
if (!matchesActionPath(new URL(request.url).pathname, path)) return new Response("Not Found", { status: 404 });
|
|
758
753
|
if (transport === "http" && request.method !== "POST") return methodNotAllowed();
|
|
759
754
|
if (sameOrigin && !isSameOrigin(request)) return forbidden();
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
755
|
+
return withRequestEntry(async () => {
|
|
756
|
+
const rawBody = ensureNdjsonBody(await request.arrayBuffer());
|
|
757
|
+
const requestIds = extractJsonRpcRequestIds(rawBody);
|
|
758
|
+
const headers = new Headers(request.headers);
|
|
759
|
+
headers.set("content-type", NDJSON_CONTENT);
|
|
760
|
+
const forwarded = new Request(request.url, {
|
|
761
|
+
method: request.method,
|
|
762
|
+
headers,
|
|
763
|
+
body: rawBody,
|
|
764
|
+
signal: request.signal
|
|
765
|
+
});
|
|
766
|
+
const extra = await options.createContext?.(forwarded) ?? {};
|
|
767
|
+
const { handler } = bundleFor(group, handlers, path, transport);
|
|
768
|
+
const response = await runWithRequest(forwarded, () => handler(forwarded), extra);
|
|
769
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
770
|
+
if (contentType.includes("application/json-rpc") || contentType.includes("ndjson")) return scrubJsonResponse(response, requestIds);
|
|
771
|
+
if (contentType.includes("json")) return scrubBufferedJson(response, requestIds);
|
|
772
|
+
return response;
|
|
769
773
|
});
|
|
770
|
-
const extra = await options.createContext?.(forwarded) ?? {};
|
|
771
|
-
const { handler } = bundleFor(group, handlers, path, transport);
|
|
772
|
-
const response = await runWithRequest(forwarded, () => handler(forwarded), extra);
|
|
773
|
-
const contentType = response.headers.get("content-type") ?? "";
|
|
774
|
-
if (contentType.includes("application/json-rpc") || contentType.includes("ndjson")) return scrubJsonResponse(response, requestIds);
|
|
775
|
-
if (contentType.includes("json")) return scrubBufferedJson(response, requestIds);
|
|
776
|
-
return response;
|
|
777
774
|
};
|
|
778
775
|
}
|
|
779
776
|
function disposeActionHandler(group, path = ACTION_PATH, transport = "http") {
|
package/dist/rpc.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as ActionContext } from "./context-
|
|
1
|
+
import { t as ActionContext } from "./context-Ct8u5XUC.mjs";
|
|
2
2
|
import { RpcClientOptions, createClient } from "./rpc/client.mjs";
|
|
3
3
|
import { Layer, Stream } from "effect";
|
|
4
4
|
import { Rpc, RpcGroup } from "effect/unstable/rpc";
|
|
@@ -38,8 +38,11 @@ declare function createWsHooks(group: RpcGroup.RpcGroup<Rpc.Any>, handlers: Laye
|
|
|
38
38
|
//#region src/rpc/stream.d.ts
|
|
39
39
|
declare function asyncGenToStream<T>(gen: AsyncGenerator<T, unknown, unknown>): Stream.Stream<T, Error, never>;
|
|
40
40
|
/**
|
|
41
|
-
* Re-enter `run` for every generator pull so
|
|
42
|
-
*
|
|
41
|
+
* Re-enter `run` for every generator pull so request context stays available
|
|
42
|
+
* across yields (Effect may drain the stream after the outer ALS scope ends;
|
|
43
|
+
* WebContainer also loses ALS across awaits, so `run` must reinstall the store).
|
|
44
|
+
* On WebContainer, pulls are serialized through settlement so concurrent streams
|
|
45
|
+
* cannot replace the sync fallback mid-pull. `withRequestEntry` is unchanged.
|
|
43
46
|
*/
|
|
44
47
|
declare function bindAsyncGenContext<T>(gen: AsyncGenerator<T, unknown, unknown>, run: <R>(fn: () => R) => R): AsyncGenerator<T, unknown, unknown>;
|
|
45
48
|
/** Create a generator inside `run`, then keep every subsequent pull inside `run`. */
|
package/dist/rpc.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as extractJsonRpcRequestIds, c as scrubRpcMessage, i as ensureNdjsonBody, n as createActionHandler, o as scrubNdjsonTransform, r as disposeActionHandler, s as scrubRpcJson, t as createWsHooks } from "./rpc-
|
|
2
|
-
import { a as streamToAsyncGen, i as bindAsyncGenContext, n as asyncGenToStream, r as asyncGenToStreamInContext, t as createClient } from "./client-
|
|
1
|
+
import { a as extractJsonRpcRequestIds, c as scrubRpcMessage, i as ensureNdjsonBody, n as createActionHandler, o as scrubNdjsonTransform, r as disposeActionHandler, s as scrubRpcJson, t as createWsHooks } from "./rpc-tYqxQToi.mjs";
|
|
2
|
+
import { a as streamToAsyncGen, i as bindAsyncGenContext, n as asyncGenToStream, r as asyncGenToStreamInContext, t as createClient } from "./client-BgBfkZDx.mjs";
|
|
3
3
|
export { asyncGenToStream, asyncGenToStreamInContext, bindAsyncGenContext, createActionHandler, createClient, createWsHooks, disposeActionHandler, ensureNdjsonBody, extractJsonRpcRequestIds, scrubNdjsonTransform, scrubRpcJson, scrubRpcMessage, streamToAsyncGen };
|
package/dist/rsbuild.mjs
CHANGED
package/dist/vite.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,42 +0,0 @@
|
|
|
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 };
|