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,601 @@
1
+ import { C as scanServerFiles, S as pluginShouldStub, _ as matchesActionPath, a as RequestBodyTooLargeError, b as parseExportedNames, c as VIRTUAL_WORKER_ID, d as generateActionsModule, f as generateClientModule, g as loadClientStub, h as isServerFileId, i as RESOLVED_VIRTUAL_WORKER_ID, m as generateWorkerWrapper, n as RESOLVED_VIRTUAL_ACTIONS_ID, o as VIRTUAL_ACTIONS_ID, p as generateClientStub, r as RESOLVED_VIRTUAL_CLIENT_ID, t as ACTION_PATH, u as generateActionsClientModule, v as moduleKey, w as sendWebResponseFrom, x as parseStreamExports, y as nodeToWebRequest } from "./actions-DE6p5Cyp.mjs";
2
+ import { n as createActionHandler, t as createWsHooks } from "./rpc-DYFEdah8.mjs";
3
+ import { ensureWorkerDom } from "./worker-dom.mjs";
4
+ import { createUnplugin } from "unplugin";
5
+ import fs from "node:fs";
6
+ import path from "node:path";
7
+ import { fileURLToPath, pathToFileURL } from "node:url";
8
+ //#region src/core.ts
9
+ const CELLD_ALLOWED_KEYS = [
10
+ "name",
11
+ "main",
12
+ "compatibility_date",
13
+ "compatibility_flags",
14
+ "durable_objects",
15
+ "migrations",
16
+ "assets",
17
+ "services",
18
+ "vars"
19
+ ];
20
+ const USER_FORBIDDEN_KEYS = ["main", "assets"];
21
+ function createEmitState() {
22
+ return { emitted: false };
23
+ }
24
+ function validateWranglerOptions(wrangler) {
25
+ const allowed = CELLD_ALLOWED_KEYS;
26
+ const invalid = Object.keys(wrangler).filter((key) => !allowed.includes(key));
27
+ if (invalid.length) throw new Error(`oxidejs: these wrangler keys are not supported by celld deploy: ${invalid.join(", ")}`);
28
+ const forbidden = USER_FORBIDDEN_KEYS.filter((key) => key in wrangler);
29
+ if (forbidden.length) throw new Error(`oxidejs: wrangler keys ${forbidden.join(", ")} are computed by the plugin and cannot be user-supplied`);
30
+ }
31
+ function assertContained(outDirAbs, childAbs, label) {
32
+ const outDir = path.resolve(outDirAbs);
33
+ const child = path.resolve(childAbs);
34
+ const relative = path.relative(outDir, child);
35
+ if (relative === "" || relative.startsWith("..") || path.isAbsolute(relative)) throw new Error(`oxidejs: ${label} must resolve inside outDir (got ${relative || "."})`);
36
+ }
37
+ function requireWranglerFields(wrangler) {
38
+ if (!wrangler?.name || !wrangler.compatibility_date) throw new Error("oxidejs: wrangler.name and wrangler.compatibility_date are required when emitConfig is true");
39
+ return wrangler;
40
+ }
41
+ function flattenInput(input) {
42
+ if (!input) return [];
43
+ if (typeof input === "string") return [input];
44
+ if (Array.isArray(input)) return input;
45
+ return Object.values(input);
46
+ }
47
+ function envInput(env) {
48
+ if (!env || typeof env !== "object") return;
49
+ const rec = env;
50
+ return rec.build?.rolldownOptions?.input || rec.build?.rollupOptions?.input || rec.build?.input || rec.input;
51
+ }
52
+ /** Vite client input: rolldown/rollup `input`, else `path.resolve(root, "index.html")`. */
53
+ function hasHtmlEntry(root, config) {
54
+ const cfg = config;
55
+ return flattenInput(envInput(cfg?.environments?.["client"]) || envInput(cfg?.environments?.["web"]) || cfg?.build?.rolldownOptions?.input || cfg?.build?.rollupOptions?.input || path.resolve(root, "index.html")).some((entry) => {
56
+ const file = path.resolve(root, entry);
57
+ return file.endsWith(".html") && fs.existsSync(file);
58
+ });
59
+ }
60
+ function resolveActions(raw) {
61
+ if (raw === void 0 || typeof raw === "string") {
62
+ const transport = raw ?? "http";
63
+ if (transport !== "http" && transport !== "ws") throw new Error(`oxidejs: unknown actions transport "${String(transport)}"`);
64
+ return {
65
+ transport,
66
+ path: ACTION_PATH,
67
+ sameOrigin: true
68
+ };
69
+ }
70
+ const transport = raw.transport ?? "http";
71
+ if (transport !== "http" && transport !== "ws") throw new Error(`oxidejs: unknown actions transport "${String(transport)}"`);
72
+ const path = raw.path ?? "/__oxide/action";
73
+ if (!path.startsWith("/") || path.includes("?")) throw new Error(`oxidejs: actions.path must start with "/" and contain no query string (got "${path}")`);
74
+ return {
75
+ transport,
76
+ path,
77
+ sameOrigin: raw.sameOrigin ?? true
78
+ };
79
+ }
80
+ function resolveOptions(raw, root, config) {
81
+ const preset = raw?.preset ?? "fetch";
82
+ if (preset !== "fetch" && preset !== "celld") throw new Error(`oxidejs: unknown preset "${String(preset)}"`);
83
+ const { transport: actions, path: actionPath, sameOrigin: actionSameOrigin } = resolveActions(raw?.actions);
84
+ if (actions === "ws" && preset === "celld") throw new Error("oxidejs: actions: \"ws\" is not supported with preset: \"celld\"");
85
+ const workerEntry = raw?.workerEntry ?? "src/server.ts";
86
+ const outDirInput = raw?.outDir ?? "dist";
87
+ const clientDir = raw?.clientDir ?? "client";
88
+ const emitConfig = raw?.emitConfig ?? preset === "celld";
89
+ const rootAbs = path.resolve(root);
90
+ const outDir = path.resolve(rootAbs, outDirInput);
91
+ const workerEntryAbs = path.resolve(rootAbs, workerEntry);
92
+ const hasClient = hasHtmlEntry(rootAbs, config);
93
+ const hasPublic = fs.existsSync(path.join(rootAbs, "public"));
94
+ if (hasClient || hasPublic) assertContained(outDir, path.resolve(outDir, clientDir), "clientDir");
95
+ if (raw?.wrangler) validateWranglerOptions(raw.wrangler);
96
+ return {
97
+ root: rootAbs,
98
+ preset,
99
+ workerEntry,
100
+ workerEntryAbs,
101
+ outDir,
102
+ clientDir,
103
+ wrangler: emitConfig ? requireWranglerFields(raw?.wrangler) : raw?.wrangler,
104
+ emitConfig,
105
+ hasClient,
106
+ hasPublic,
107
+ actions,
108
+ actionPath,
109
+ actionSameOrigin,
110
+ actionHeaders: raw?.actionHeaders,
111
+ middleware: raw?.middleware ?? [],
112
+ imports: raw?.imports ?? [],
113
+ bodyLimit: raw?.bodyLimit ?? 1048576,
114
+ notFound: raw?.notFound,
115
+ env: raw?.env
116
+ };
117
+ }
118
+ function copyPublicDir(opts) {
119
+ if (opts.preset !== "fetch") return;
120
+ const src = path.join(opts.root, "public");
121
+ if (!fs.existsSync(src)) return;
122
+ fs.cpSync(src, path.join(opts.outDir, opts.clientDir), {
123
+ recursive: true,
124
+ force: true
125
+ });
126
+ }
127
+ function tryEmitWranglerConfig(opts, state) {
128
+ if (state.emitted || opts.emitConfig === false) return;
129
+ const wrangler = requireWranglerFields(opts.wrangler);
130
+ const serverFile = path.join(opts.outDir, "server.js");
131
+ const clientDirPath = path.join(opts.outDir, opts.clientDir);
132
+ if (!fs.existsSync(serverFile)) return;
133
+ if (opts.hasClient && !fs.existsSync(clientDirPath)) return;
134
+ assertContained(opts.outDir, serverFile, "main");
135
+ if (opts.hasClient) assertContained(opts.outDir, clientDirPath, "assets.directory");
136
+ const config = {
137
+ name: wrangler.name,
138
+ main: "./server.js",
139
+ compatibility_date: wrangler.compatibility_date,
140
+ compatibility_flags: [.../* @__PURE__ */ new Set([...wrangler.compatibility_flags ?? [], "nodejs_compat"])],
141
+ ...wrangler.durable_objects ? { durable_objects: wrangler.durable_objects } : {},
142
+ ...wrangler.migrations ? { migrations: wrangler.migrations } : {},
143
+ ...wrangler.services ? { services: wrangler.services } : {},
144
+ ...wrangler.vars ? { vars: wrangler.vars } : {},
145
+ ...opts.hasClient ? { assets: {
146
+ directory: `./${opts.clientDir}`,
147
+ binding: "ASSETS"
148
+ } } : {}
149
+ };
150
+ fs.writeFileSync(path.join(opts.outDir, "wrangler.jsonc"), `${JSON.stringify(config, null, 2)}\n`);
151
+ state.emitted = true;
152
+ }
153
+ //#endregion
154
+ //#region src/worker-build.ts
155
+ /** Dev aliases so Vite transforms RPC helpers with the app's single effect copy. */
156
+ function oxideRpcAliases() {
157
+ const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
158
+ const client = path.join(root, "src/rpc/client.ts");
159
+ if (!fs.existsSync(client)) return [];
160
+ return [{
161
+ find: /^oxidejs\/rpc\/client$/,
162
+ replacement: client
163
+ }, {
164
+ find: /^oxidejs\/rpc$/,
165
+ replacement: path.join(root, "src/rpc/index.ts")
166
+ }];
167
+ }
168
+ function mergeAliases(config, extra) {
169
+ if (extra.length === 0) return;
170
+ config.resolve ??= {};
171
+ const current = config.resolve.alias;
172
+ if (!current) {
173
+ config.resolve.alias = extra;
174
+ return;
175
+ }
176
+ if (Array.isArray(current)) {
177
+ config.resolve.alias = [...current, ...extra];
178
+ return;
179
+ }
180
+ config.resolve.alias = [...Object.entries(current).map(([find, replacement]) => ({
181
+ find,
182
+ replacement
183
+ })), ...extra];
184
+ }
185
+ const EFFECT_DEPS = [
186
+ "effect",
187
+ "effect/unstable/rpc",
188
+ "effect/unstable/http",
189
+ "effect/unstable/socket"
190
+ ];
191
+ function applyViteEnvironments(config, opts) {
192
+ config.builder ??= {};
193
+ config.resolve ??= {};
194
+ const dedupe = /* @__PURE__ */ new Set([
195
+ ...Array.isArray(config.resolve.dedupe) ? config.resolve.dedupe : [],
196
+ "effect",
197
+ "oxidejs"
198
+ ]);
199
+ config.resolve.dedupe = [...dedupe];
200
+ config.optimizeDeps ??= {};
201
+ const optimizeInclude = /* @__PURE__ */ new Set([...Array.isArray(config.optimizeDeps.include) ? config.optimizeDeps.include : [], ...EFFECT_DEPS]);
202
+ config.optimizeDeps.include = [...optimizeInclude];
203
+ const celld = opts.preset === "celld";
204
+ mergeAliases(config, oxideRpcAliases());
205
+ config.environments ??= {};
206
+ config.environments["ssr"] = {
207
+ consumer: "server",
208
+ build: {
209
+ outDir: opts.outDir,
210
+ emptyOutDir: true,
211
+ ssr: true,
212
+ rolldownOptions: {
213
+ input: VIRTUAL_WORKER_ID,
214
+ external: celld ? [/^cloudflare:/] : [],
215
+ output: {
216
+ format: "es",
217
+ entryFileNames: "server.js"
218
+ }
219
+ },
220
+ rollupOptions: {
221
+ input: VIRTUAL_WORKER_ID,
222
+ external: celld ? [/^cloudflare:/] : [],
223
+ output: {
224
+ format: "es",
225
+ entryFileNames: "server.js"
226
+ }
227
+ }
228
+ },
229
+ resolve: celld ? {
230
+ conditions: ["worker"],
231
+ noExternal: true
232
+ } : { noExternal: ["effect", "oxidejs"] },
233
+ ssr: celld ? {
234
+ target: "webworker",
235
+ noExternal: true,
236
+ external: [/^cloudflare:/]
237
+ } : { noExternal: ["effect", "oxidejs"] }
238
+ };
239
+ config.build ??= {};
240
+ if (opts.hasClient) {
241
+ const clientOutDir = path.join(opts.outDir, opts.clientDir);
242
+ const existingClient = config.environments["client"];
243
+ config.environments["client"] = {
244
+ ...existingClient,
245
+ consumer: "client",
246
+ build: {
247
+ ...existingClient?.build,
248
+ outDir: clientOutDir,
249
+ emptyOutDir: true,
250
+ manifest: true
251
+ }
252
+ };
253
+ config.environments["ssr"].build.emptyOutDir = false;
254
+ config.build.outDir ??= clientOutDir;
255
+ config.build.manifest ??= true;
256
+ } else {
257
+ delete config.environments["client"];
258
+ config.appType = "custom";
259
+ config.build.outDir ??= opts.outDir;
260
+ config.build.emptyOutDir ??= true;
261
+ config.builder.buildApp ??= async (builder) => {
262
+ const server = builder.environments["ssr"];
263
+ if (server) await builder.build(server);
264
+ };
265
+ }
266
+ return config;
267
+ }
268
+ function applyRsbuildEnvironments(config, opts) {
269
+ config.environments ??= {};
270
+ if (opts.hasClient) {
271
+ const clientOutDir = path.join(opts.outDir, opts.clientDir);
272
+ const existingClient = config.environments["web"] ?? config.environments["client"];
273
+ config.environments["web"] = {
274
+ ...existingClient,
275
+ output: {
276
+ ...existingClient?.output,
277
+ target: "web",
278
+ distPath: {
279
+ ...existingClient?.output?.distPath,
280
+ root: clientOutDir
281
+ },
282
+ manifest: true
283
+ }
284
+ };
285
+ } else {
286
+ delete config.environments["web"];
287
+ delete config.environments["client"];
288
+ }
289
+ const server = {
290
+ source: { entry: { server: {
291
+ import: VIRTUAL_WORKER_ID,
292
+ html: false
293
+ } } },
294
+ output: {
295
+ target: opts.preset === "celld" ? "web-worker" : "node",
296
+ filename: { js: "server.js" },
297
+ distPath: { root: opts.outDir }
298
+ }
299
+ };
300
+ if (opts.preset === "celld") server.resolve = { conditionNames: ["worker", "..."] };
301
+ config.environments["server"] = server;
302
+ return config;
303
+ }
304
+ //#endregion
305
+ //#region src/plugin.ts
306
+ function actionMiddleware(loadRouter, loadRpc, path, sameOrigin, bodyLimit, onError) {
307
+ return (req, res, next) => {
308
+ if (!matchesActionPath((req.url ?? "").split("?")[0] ?? "", path)) {
309
+ next();
310
+ return;
311
+ }
312
+ (async () => {
313
+ const [mod, rpc] = await Promise.all([loadRouter(), loadRpc()]);
314
+ const response = await rpc.createActionHandler(mod.default, mod.actionsHandlers, {
315
+ path,
316
+ sameOrigin
317
+ })(await nodeToWebRequest(req, bodyLimit));
318
+ await sendWebResponseFrom(req, res, response);
319
+ })().catch((error) => {
320
+ if (res.headersSent) return;
321
+ if (error instanceof RequestBodyTooLargeError) {
322
+ res.statusCode = 413;
323
+ res.end();
324
+ return;
325
+ }
326
+ onError?.(error);
327
+ res.statusCode = 503;
328
+ res.setHeader("content-type", "application/json");
329
+ res.end(JSON.stringify({ error: "oxide action handler failed" }));
330
+ });
331
+ };
332
+ }
333
+ function attachActionUpgrade(httpServer, loadRouter, loadRpc, path, sameOrigin) {
334
+ if (!httpServer) return;
335
+ import(
336
+ /* @vite-ignore */
337
+ "crossws/adapters/node"
338
+ ).then(({ default: crossws }) => {
339
+ httpServer.on("upgrade", (req, socket, head) => {
340
+ if (!matchesActionPath((req.url ?? "").split("?")[0] ?? "", path)) return;
341
+ Promise.all([loadRouter(), loadRpc()]).then(([mod, rpc]) => crossws({ hooks: rpc.createWsHooks(mod.default, mod.actionsHandlers, {
342
+ path,
343
+ sameOrigin
344
+ }) }).handleUpgrade(req, socket, head)).catch(() => {
345
+ socket.destroy();
346
+ });
347
+ });
348
+ });
349
+ }
350
+ function previewMiddleware(file) {
351
+ return (req, res, next) => {
352
+ (async () => {
353
+ const mod = await import(
354
+ /* @vite-ignore */
355
+ pathToFileURL(file).href
356
+ );
357
+ await sendWebResponseFrom(req, res, await mod.default.fetch(await nodeToWebRequest(req)));
358
+ })().catch(next);
359
+ };
360
+ }
361
+ function loadActions(root) {
362
+ const code = generateActionsModule(scanServerFiles(root), { bust: true });
363
+ const dir = fs.mkdtempSync(path.join(root, ".oxide-actions-"));
364
+ const file = path.join(dir, "actions.mjs");
365
+ fs.writeFileSync(file, code);
366
+ return import(pathToFileURL(file).href).finally(() => {
367
+ fs.rmSync(dir, {
368
+ recursive: true,
369
+ force: true
370
+ });
371
+ });
372
+ }
373
+ const unpluginFactory = (options) => {
374
+ let resolved;
375
+ const emitState = createEmitState();
376
+ return {
377
+ name: "oxidejs",
378
+ enforce: "pre",
379
+ buildStart() {
380
+ resolved ??= resolveOptions(options, process.cwd());
381
+ emitState.emitted = false;
382
+ },
383
+ resolveId(id) {
384
+ if (id === "virtual:oxide/actions") return RESOLVED_VIRTUAL_ACTIONS_ID;
385
+ if (id === "virtual:oxide/worker") return RESOLVED_VIRTUAL_WORKER_ID;
386
+ if (id === "virtual:oxide/client") return RESOLVED_VIRTUAL_CLIENT_ID;
387
+ return null;
388
+ },
389
+ load(id, extra) {
390
+ if (id === RESOLVED_VIRTUAL_CLIENT_ID) {
391
+ const transport = resolved?.actions ?? (typeof options?.actions === "string" || options?.actions === void 0 ? options?.actions : options.actions.transport) ?? "http";
392
+ return generateClientModule(transport, resolved?.actionHeaders ?? options?.actionHeaders, resolved?.actionPath);
393
+ }
394
+ if (id === RESOLVED_VIRTUAL_WORKER_ID && pluginShouldStub(this, extra)) throw new Error(`oxidejs: ${VIRTUAL_WORKER_ID} is server-only`);
395
+ if (id === RESOLVED_VIRTUAL_ACTIONS_ID) {
396
+ const modules = scanServerFiles(resolved?.root ?? process.cwd());
397
+ if (pluginShouldStub(this, extra)) return generateActionsClientModule(modules);
398
+ for (const mod of modules) this.addWatchFile(mod.abs);
399
+ return generateActionsModule(modules);
400
+ }
401
+ if (id === RESOLVED_VIRTUAL_WORKER_ID) {
402
+ if (!resolved) return;
403
+ this.addWatchFile(resolved.workerEntryAbs);
404
+ const modules = scanServerFiles(resolved.root);
405
+ for (const mod of modules) this.addWatchFile(mod.abs);
406
+ return generateWorkerWrapper(resolved.workerEntryAbs, {
407
+ preset: resolved.preset,
408
+ clientDir: resolved.clientDir,
409
+ hasClient: resolved.hasClient,
410
+ hasPublic: resolved.hasPublic,
411
+ hasActions: modules.length > 0,
412
+ actions: resolved.actions,
413
+ actionPath: resolved.actionPath,
414
+ actionSameOrigin: resolved.actionSameOrigin,
415
+ middleware: resolved.middleware,
416
+ imports: resolved.imports,
417
+ bodyLimit: resolved.bodyLimit,
418
+ notFound: resolved.notFound,
419
+ env: resolved.env
420
+ });
421
+ }
422
+ if (isServerFileId(id) && pluginShouldStub(this, extra)) {
423
+ const file = id.split("?")[0] ?? id;
424
+ this.addWatchFile(file);
425
+ return loadClientStub(id);
426
+ }
427
+ },
428
+ transform(code, id, extra) {
429
+ if (!isServerFileId(id) || !pluginShouldStub(this, extra) || code.startsWith("// oxidejs:client-stub\n")) return;
430
+ return generateClientStub({
431
+ key: moduleKey(id.split("?")[0] ?? id),
432
+ exports: parseExportedNames(code),
433
+ streams: parseStreamExports(code)
434
+ });
435
+ },
436
+ vite: {
437
+ config(config) {
438
+ resolved = resolveOptions(options, typeof config.root === "string" ? config.root : process.cwd(), config);
439
+ applyViteEnvironments(config, resolved);
440
+ },
441
+ configureServer(server) {
442
+ if (resolved?.preset === "celld") {
443
+ ensureWorkerDom();
444
+ const ssr = server.environments.ssr;
445
+ const resolve = ssr?.config?.resolve;
446
+ if (resolve) {
447
+ resolve.conditions = [
448
+ "node",
449
+ "import",
450
+ "module",
451
+ "default"
452
+ ];
453
+ resolve.noExternal = ["effect", "oxidejs"];
454
+ }
455
+ const ssrOpts = ssr?.config?.ssr;
456
+ if (ssrOpts && typeof ssrOpts === "object") {
457
+ ssrOpts.target = "node";
458
+ ssrOpts.noExternal = ["effect", "oxidejs"];
459
+ }
460
+ }
461
+ const invalidateActions = () => {
462
+ for (const env of Object.values(server.environments)) {
463
+ const mod = env.moduleGraph.getModuleById(RESOLVED_VIRTUAL_ACTIONS_ID);
464
+ if (mod) env.moduleGraph.invalidateModule(mod);
465
+ }
466
+ };
467
+ const fetchRouter = async () => {
468
+ return await server.ssrLoadModule(VIRTUAL_ACTIONS_ID);
469
+ };
470
+ let routerReady;
471
+ const loadRouter = () => {
472
+ const current = routerReady ??= fetchRouter();
473
+ return current.catch((error) => {
474
+ if (routerReady === current) routerReady = void 0;
475
+ throw error;
476
+ });
477
+ };
478
+ const refreshRouter = () => {
479
+ routerReady = void 0;
480
+ };
481
+ server.watcher.on("all", (_event, file) => {
482
+ if (isServerFileId(file)) {
483
+ invalidateActions();
484
+ refreshRouter();
485
+ }
486
+ });
487
+ const loadRpc = () => server.ssrLoadModule("oxidejs/rpc");
488
+ const logActionError = (error) => {
489
+ server.config.logger.error("oxidejs: action handler failed: " + String(error));
490
+ };
491
+ const wireActions = () => server.middlewares.use(actionMiddleware(loadRouter, loadRpc, resolved.actionPath, resolved.actionSameOrigin, resolved.bodyLimit, logActionError));
492
+ if (resolved?.actions === "ws") {
493
+ attachActionUpgrade(server.httpServer, loadRouter, loadRpc, resolved.actionPath, resolved.actionSameOrigin);
494
+ return async () => {
495
+ try {
496
+ await loadRouter();
497
+ } catch (error) {
498
+ server.config.logger.error("oxidejs: failed to prewarm actions: " + String(error));
499
+ }
500
+ };
501
+ }
502
+ let handlersPromise = Promise.resolve([]);
503
+ if ((resolved?.middleware?.length ?? 0) > 0 || (resolved?.imports?.length ?? 0) > 0) {
504
+ handlersPromise = (async () => {
505
+ try {
506
+ for (const spec of resolved.imports ?? []) await server.ssrLoadModule(spec);
507
+ const handlers = [];
508
+ for (const entry of resolved.middleware ?? []) {
509
+ const spec = typeof entry === "string" ? entry : entry.module;
510
+ const mod = await server.ssrLoadModule(spec);
511
+ if (typeof mod.default !== "function") continue;
512
+ const fn = mod.default;
513
+ handlers.push((request, context) => Promise.resolve(fn(request, context)));
514
+ }
515
+ return handlers;
516
+ } catch (error) {
517
+ server.config.logger.error("oxidejs: failed to wire dev middleware: " + String(error));
518
+ return [];
519
+ }
520
+ })();
521
+ server.middlewares.use((creq, cres, next) => {
522
+ if (matchesActionPath((creq.url ?? "").split("?")[0] ?? "", resolved.actionPath)) {
523
+ next();
524
+ return;
525
+ }
526
+ (async () => {
527
+ try {
528
+ const handlers = await handlersPromise;
529
+ if (handlers.length === 0) {
530
+ next();
531
+ return;
532
+ }
533
+ const { nodeToWebRequest, sendWebResponseFrom } = await import("./actions-DE6p5Cyp.mjs").then((n) => n.l);
534
+ const request = await nodeToWebRequest(creq, resolved.bodyLimit);
535
+ const context = {
536
+ env: resolved.env,
537
+ ctx: void 0
538
+ };
539
+ for (const handler of handlers) {
540
+ const hit = await handler(request, context);
541
+ if (hit) {
542
+ await sendWebResponseFrom(creq, cres, hit);
543
+ return;
544
+ }
545
+ }
546
+ next();
547
+ } catch (error) {
548
+ if (cres.headersSent) return;
549
+ cres.statusCode = error instanceof RequestBodyTooLargeError ? 413 : 500;
550
+ cres.end(error instanceof RequestBodyTooLargeError ? void 0 : String(error));
551
+ }
552
+ })();
553
+ });
554
+ }
555
+ wireActions();
556
+ return async () => {
557
+ try {
558
+ await loadRouter();
559
+ await handlersPromise;
560
+ } catch (error) {
561
+ server.config.logger.error("oxidejs: failed to prewarm dev server: " + String(error));
562
+ }
563
+ };
564
+ },
565
+ configurePreviewServer(server) {
566
+ if (resolved?.preset !== "fetch") return;
567
+ server.middlewares.use(previewMiddleware(path.join(resolved.outDir, "server.js")));
568
+ }
569
+ },
570
+ rsbuild: { setup(api) {
571
+ api.modifyRsbuildConfig((config) => {
572
+ resolved = resolveOptions(options, typeof config.root === "string" ? config.root : process.cwd(), config);
573
+ applyRsbuildEnvironments(config, resolved);
574
+ });
575
+ api.onBeforeStartDevServer(({ server }) => {
576
+ const loadRouter = async () => {
577
+ return loadActions(resolved?.root ?? process.cwd());
578
+ };
579
+ const loadRpc = async () => ({
580
+ createActionHandler,
581
+ createWsHooks
582
+ });
583
+ if (resolved?.actions === "ws") attachActionUpgrade(server.httpServer, loadRouter, loadRpc, resolved.actionPath, resolved.actionSameOrigin);
584
+ else server.middlewares.use(actionMiddleware(loadRouter, loadRpc, resolved.actionPath, resolved.actionSameOrigin, resolved.bodyLimit));
585
+ });
586
+ api.onBeforeStartPreviewServer?.(({ server }) => {
587
+ if (resolved?.preset !== "fetch") return;
588
+ server.middlewares.use(previewMiddleware(path.join(resolved.outDir, "server.js")));
589
+ });
590
+ } },
591
+ writeBundle() {
592
+ if (!resolved) return;
593
+ copyPublicDir(resolved);
594
+ tryEmitWranglerConfig(resolved, emitState);
595
+ }
596
+ };
597
+ };
598
+ const oxidejs = /* @__PURE__ */ createUnplugin(unpluginFactory);
599
+ const vite = /* @__PURE__ */ (() => oxidejs.vite)();
600
+ //#endregion
601
+ export { unpluginFactory as n, vite as r, oxidejs as t };
package/dist/plugin.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { n as unpluginFactory, r as vite, t as oxidejs } from "./plugin-nO0yjtk0.mjs";
1
+ import { n as unpluginFactory, r as vite, t as oxidejs } from "./plugin-IQa_lKkT.mjs";
2
2
  export { oxidejs as default, oxidejs, unpluginFactory, vite };
@@ -0,0 +1,13 @@
1
+ import { t as OxidejsActionHeaders } from "../types-BM4NAnzy.mjs";
2
+ import { Rpc, RpcGroup } from "effect/unstable/rpc";
3
+ //#region src/rpc/client.d.ts
4
+ type RpcClientOptions = {
5
+ url: string;
6
+ transport?: "http" | "ws";
7
+ headers?: OxidejsActionHeaders;
8
+ };
9
+ type NestedClient = Record<string, Record<string, (...args: unknown[]) => Promise<unknown> | AsyncGenerator<unknown>>>;
10
+ type ActionGroup = RpcGroup.RpcGroup<Rpc.Any>;
11
+ declare function createClient(group: ActionGroup, options: RpcClientOptions): NestedClient;
12
+ //#endregion
13
+ export { RpcClientOptions, createClient };
@@ -0,0 +1,2 @@
1
+ import { t as createClient } from "../client-Bc4g9AEw.mjs";
2
+ export { createClient };