rwsdk 1.0.4 → 1.0.6
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/dist/runtime/lib/router.js +10 -20
- package/dist/runtime/lib/router.test.js +91 -1
- package/dist/runtime/register/methodEnforcer.d.ts +8 -0
- package/dist/runtime/register/methodEnforcer.js +41 -0
- package/dist/runtime/register/methodEnforcer.test.d.ts +1 -0
- package/dist/runtime/register/methodEnforcer.test.js +128 -0
- package/dist/runtime/register/worker.js +2 -24
- package/package.json +11 -10
|
@@ -206,7 +206,6 @@ export function defineRoutes(routes) {
|
|
|
206
206
|
throw error;
|
|
207
207
|
}
|
|
208
208
|
// --- Main flow ---
|
|
209
|
-
let firstRouteDefinitionEncountered = false;
|
|
210
209
|
let actionHandled = false;
|
|
211
210
|
const handleAction = async () => {
|
|
212
211
|
// Handle RSC actions once per request, based on the incoming URL.
|
|
@@ -241,17 +240,6 @@ export function defineRoutes(routes) {
|
|
|
241
240
|
currentRouteIndex++;
|
|
242
241
|
continue;
|
|
243
242
|
}
|
|
244
|
-
// This is a RouteDefinition (route.type === "definition").
|
|
245
|
-
// The first time we see one, we handle any RSC actions.
|
|
246
|
-
if (!firstRouteDefinitionEncountered) {
|
|
247
|
-
firstRouteDefinitionEncountered = true;
|
|
248
|
-
try {
|
|
249
|
-
await handleAction();
|
|
250
|
-
}
|
|
251
|
-
catch (error) {
|
|
252
|
-
return await executeExceptHandlers(error, currentRouteIndex);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
243
|
let params = null;
|
|
256
244
|
if (route.isStatic) {
|
|
257
245
|
if (route.path === path) {
|
|
@@ -310,6 +298,9 @@ export function defineRoutes(routes) {
|
|
|
310
298
|
return handled;
|
|
311
299
|
}
|
|
312
300
|
}
|
|
301
|
+
// All global and route-specific middlewares have run, so it's
|
|
302
|
+
// safe to handle any pending RSC action before rendering.
|
|
303
|
+
await handleAction();
|
|
313
304
|
// Final component/handler
|
|
314
305
|
if (isRouteComponent(componentHandler)) {
|
|
315
306
|
const requestInfo = getRequestInfo();
|
|
@@ -365,14 +356,13 @@ Route handlers must return one of:
|
|
|
365
356
|
}
|
|
366
357
|
}
|
|
367
358
|
// If we've gotten this far, no route was matched.
|
|
368
|
-
//
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
}
|
|
359
|
+
// All global middlewares have already executed, so it's safe to handle
|
|
360
|
+
// any pending RSC action before returning the 404 response.
|
|
361
|
+
try {
|
|
362
|
+
await handleAction();
|
|
363
|
+
}
|
|
364
|
+
catch (error) {
|
|
365
|
+
return await executeExceptHandlers(error, compiledRoutes.length - 1);
|
|
376
366
|
}
|
|
377
367
|
return new Response("Not Found", { status: 404 });
|
|
378
368
|
}
|
|
@@ -404,7 +404,7 @@ describe("defineRoutes - Request Handling Behavior", () => {
|
|
|
404
404
|
});
|
|
405
405
|
});
|
|
406
406
|
describe("RSC Action Handling", () => {
|
|
407
|
-
it("should handle RSC actions
|
|
407
|
+
it("should handle RSC actions after global middleware but before page rendering", async () => {
|
|
408
408
|
const executionOrder = [];
|
|
409
409
|
const middleware1 = (requestInfo) => {
|
|
410
410
|
executionOrder.push("middleware1");
|
|
@@ -473,6 +473,96 @@ describe("defineRoutes - Request Handling Behavior", () => {
|
|
|
473
473
|
expect(executionOrder).toEqual(["rscActionHandler", "PageComponent2"]);
|
|
474
474
|
// Should only call action handler once, even though there are multiple routes
|
|
475
475
|
});
|
|
476
|
+
// Regression test for issue #1110:
|
|
477
|
+
// When a route definition appears before global middleware in the flattened
|
|
478
|
+
// route list (e.g. an API route defined before a session-setup middleware),
|
|
479
|
+
// the RSC action handler was incorrectly fired at the first route definition
|
|
480
|
+
// encountered – before those later middlewares had run. Interruptors
|
|
481
|
+
// (registered via serverAction/serverQuery) execute inside rscActionHandler,
|
|
482
|
+
// so they would see an incomplete request context (e.g. ctx.user not yet set).
|
|
483
|
+
it("should run all global middleware before rscActionHandler even when a route definition appears first", async () => {
|
|
484
|
+
const executionOrder = [];
|
|
485
|
+
// A route definition that appears BEFORE global middleware
|
|
486
|
+
const apiRoute = route("/api/data/", async () => new Response(JSON.stringify({ data: "ok" })));
|
|
487
|
+
// Global middleware that sets up context (e.g. session / auth)
|
|
488
|
+
const globalMiddleware = async (requestInfo) => {
|
|
489
|
+
executionOrder.push("globalMiddleware");
|
|
490
|
+
requestInfo.ctx.user = { id: 1 };
|
|
491
|
+
};
|
|
492
|
+
const PageComponent = () => {
|
|
493
|
+
executionOrder.push("PageComponent");
|
|
494
|
+
return React.createElement("div", {}, "Page");
|
|
495
|
+
};
|
|
496
|
+
const router = defineRoutes([
|
|
497
|
+
apiRoute,
|
|
498
|
+
globalMiddleware, // global middleware defined AFTER a route definition
|
|
499
|
+
route("/test/", PageComponent),
|
|
500
|
+
]);
|
|
501
|
+
const deps = createMockDependencies();
|
|
502
|
+
deps.mockRequestInfo.request = new Request("http://localhost:3000/test/?__rsc_action_id=test");
|
|
503
|
+
deps.mockRscActionHandler = async (request) => {
|
|
504
|
+
executionOrder.push("rscActionHandler");
|
|
505
|
+
return { actionResult: "test-result" };
|
|
506
|
+
};
|
|
507
|
+
const request = new Request("http://localhost:3000/test/?__rsc_action_id=test");
|
|
508
|
+
await router.handle({
|
|
509
|
+
request,
|
|
510
|
+
renderPage: deps.mockRenderPage,
|
|
511
|
+
getRequestInfo: deps.getRequestInfo,
|
|
512
|
+
onError: deps.onError,
|
|
513
|
+
runWithRequestInfoOverrides: deps.mockRunWithRequestInfoOverrides,
|
|
514
|
+
rscActionHandler: deps.mockRscActionHandler,
|
|
515
|
+
});
|
|
516
|
+
// globalMiddleware must complete before rscActionHandler runs so that
|
|
517
|
+
// interruptors inside the action have access to ctx.user.
|
|
518
|
+
expect(executionOrder).toEqual([
|
|
519
|
+
"globalMiddleware",
|
|
520
|
+
"rscActionHandler",
|
|
521
|
+
"PageComponent",
|
|
522
|
+
]);
|
|
523
|
+
});
|
|
524
|
+
it("should handle RSC actions after route-specific middleware", async () => {
|
|
525
|
+
const executionOrder = [];
|
|
526
|
+
const globalMiddleware = async (requestInfo) => {
|
|
527
|
+
executionOrder.push("globalMiddleware");
|
|
528
|
+
requestInfo.ctx.user = { id: 1 };
|
|
529
|
+
};
|
|
530
|
+
const requireAdmin = async (requestInfo) => {
|
|
531
|
+
executionOrder.push("requireAdmin");
|
|
532
|
+
if (!requestInfo.ctx.user?.isAdmin) {
|
|
533
|
+
return new Response("Forbidden", { status: 403 });
|
|
534
|
+
}
|
|
535
|
+
};
|
|
536
|
+
const AdminPage = () => {
|
|
537
|
+
executionOrder.push("AdminPage");
|
|
538
|
+
return React.createElement("div", {}, "Admin");
|
|
539
|
+
};
|
|
540
|
+
const router = defineRoutes([
|
|
541
|
+
globalMiddleware,
|
|
542
|
+
route("/admin/", [requireAdmin, AdminPage]),
|
|
543
|
+
]);
|
|
544
|
+
const deps = createMockDependencies();
|
|
545
|
+
deps.mockRequestInfo.request = new Request("http://localhost:3000/admin/?__rsc_action_id=test");
|
|
546
|
+
deps.mockRscActionHandler = async (request) => {
|
|
547
|
+
executionOrder.push("rscActionHandler");
|
|
548
|
+
return { actionResult: "test-result" };
|
|
549
|
+
};
|
|
550
|
+
const request = new Request("http://localhost:3000/admin/?__rsc_action_id=test");
|
|
551
|
+
const response = await router.handle({
|
|
552
|
+
request,
|
|
553
|
+
renderPage: deps.mockRenderPage,
|
|
554
|
+
getRequestInfo: deps.getRequestInfo,
|
|
555
|
+
onError: deps.onError,
|
|
556
|
+
runWithRequestInfoOverrides: deps.mockRunWithRequestInfoOverrides,
|
|
557
|
+
rscActionHandler: deps.mockRscActionHandler,
|
|
558
|
+
});
|
|
559
|
+
// requireAdmin should short-circuit before the action runs
|
|
560
|
+
expect(executionOrder).toEqual([
|
|
561
|
+
"globalMiddleware",
|
|
562
|
+
"requireAdmin",
|
|
563
|
+
]);
|
|
564
|
+
expect(response.status).toBe(403);
|
|
565
|
+
});
|
|
476
566
|
});
|
|
477
567
|
describe("Page Route Matching and Rendering", () => {
|
|
478
568
|
it("should match the first route that matches the path", async () => {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
type GetServerModuleExport = (actionId: string) => Promise<unknown>;
|
|
2
|
+
type DecodeReply = (data: string | FormData, moduleMap: null) => Promise<unknown>;
|
|
3
|
+
export interface RscActionHandlerDeps {
|
|
4
|
+
getServerModuleExport: GetServerModuleExport;
|
|
5
|
+
decodeReply: DecodeReply;
|
|
6
|
+
}
|
|
7
|
+
export declare function rscActionHandler(req: Request, { getServerModuleExport, decodeReply }: RscActionHandlerDeps): Promise<unknown>;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// context(justinvdm, 2026-04-06): Extracted from rscActionHandler() for testability.
|
|
2
|
+
// The real getServerModuleExport and decodeReply require the react-server environment
|
|
3
|
+
// (virtual module lookup, react-server-dom-webpack), so we accept them as injected
|
|
4
|
+
// dependencies. worker.ts passes the real implementations; tests pass fakes.
|
|
5
|
+
export async function rscActionHandler(req, { getServerModuleExport, decodeReply }) {
|
|
6
|
+
const url = new URL(req.url);
|
|
7
|
+
const contentType = req.headers.get("content-type");
|
|
8
|
+
let args = [];
|
|
9
|
+
if (req.method === "GET") {
|
|
10
|
+
const argsParam = url.searchParams.get("args");
|
|
11
|
+
if (argsParam) {
|
|
12
|
+
args = JSON.parse(argsParam);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
const data = contentType?.startsWith("multipart/form-data")
|
|
17
|
+
? await req.formData()
|
|
18
|
+
: await req.text();
|
|
19
|
+
args = (await decodeReply(data, null));
|
|
20
|
+
}
|
|
21
|
+
const actionId = url.searchParams.get("__rsc_action_id");
|
|
22
|
+
if (import.meta.env.VITE_IS_DEV_SERVER && actionId === "__rsc_hot_update") {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const action = await getServerModuleExport(actionId);
|
|
26
|
+
if (typeof action !== "function") {
|
|
27
|
+
throw new Error(`Action ${actionId} is not a function`);
|
|
28
|
+
}
|
|
29
|
+
// context(justinvdm, 2026-04-06): Validate the declared HTTP method before
|
|
30
|
+
// invocation. serverAction() attaches .method = "POST" at creation time via
|
|
31
|
+
// createServerFunction(), serverQuery() attaches "GET". Functions without
|
|
32
|
+
// .method default to POST to match serverAction() semantics.
|
|
33
|
+
const actionMethod = action.method ?? "POST";
|
|
34
|
+
if (actionMethod !== req.method) {
|
|
35
|
+
return new Response(`Method ${req.method} is not allowed for this action. Allowed: ${actionMethod}.`, {
|
|
36
|
+
status: 405,
|
|
37
|
+
headers: { Allow: actionMethod },
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return action(...args);
|
|
41
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { rscActionHandler } from "./methodEnforcer";
|
|
3
|
+
function createDeps(action) {
|
|
4
|
+
return {
|
|
5
|
+
getServerModuleExport: vi.fn().mockResolvedValue(action),
|
|
6
|
+
decodeReply: vi.fn().mockResolvedValue([]),
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
function makeRequest(url, method, body) {
|
|
10
|
+
const init = { method };
|
|
11
|
+
if (body !== undefined) {
|
|
12
|
+
init.body = body;
|
|
13
|
+
init.headers = { "content-type": "application/json" };
|
|
14
|
+
}
|
|
15
|
+
return new Request(url, init);
|
|
16
|
+
}
|
|
17
|
+
const ACTION_URL = "https://app.test/page?__rsc_action_id=%2Factions.tsx%23doThing";
|
|
18
|
+
describe("rscActionHandler method enforcement", () => {
|
|
19
|
+
it("rejects GET for an action with method POST", async () => {
|
|
20
|
+
const action = Object.assign(vi.fn(), { method: "POST" });
|
|
21
|
+
const deps = createDeps(action);
|
|
22
|
+
const req = makeRequest(ACTION_URL, "GET");
|
|
23
|
+
const result = await rscActionHandler(req, deps);
|
|
24
|
+
expect(result).toBeInstanceOf(Response);
|
|
25
|
+
const res = result;
|
|
26
|
+
expect(res.status).toBe(405);
|
|
27
|
+
expect(res.headers.get("Allow")).toBe("POST");
|
|
28
|
+
expect(action).not.toHaveBeenCalled();
|
|
29
|
+
});
|
|
30
|
+
it("rejects POST for an action with method GET", async () => {
|
|
31
|
+
const action = Object.assign(vi.fn(), { method: "GET" });
|
|
32
|
+
const deps = createDeps(action);
|
|
33
|
+
const req = makeRequest(ACTION_URL, "POST", "[]");
|
|
34
|
+
const result = await rscActionHandler(req, deps);
|
|
35
|
+
expect(result).toBeInstanceOf(Response);
|
|
36
|
+
const res = result;
|
|
37
|
+
expect(res.status).toBe(405);
|
|
38
|
+
expect(res.headers.get("Allow")).toBe("GET");
|
|
39
|
+
expect(action).not.toHaveBeenCalled();
|
|
40
|
+
});
|
|
41
|
+
it("allows POST for an action with method POST", async () => {
|
|
42
|
+
const action = Object.assign(vi.fn().mockReturnValue("ok"), {
|
|
43
|
+
method: "POST",
|
|
44
|
+
});
|
|
45
|
+
const deps = createDeps(action);
|
|
46
|
+
const req = makeRequest(ACTION_URL, "POST", "[]");
|
|
47
|
+
const result = await rscActionHandler(req, deps);
|
|
48
|
+
expect(result).toBe("ok");
|
|
49
|
+
expect(action).toHaveBeenCalled();
|
|
50
|
+
});
|
|
51
|
+
it("allows GET for an action with method GET", async () => {
|
|
52
|
+
const action = Object.assign(vi.fn().mockReturnValue("data"), {
|
|
53
|
+
method: "GET",
|
|
54
|
+
});
|
|
55
|
+
const deps = createDeps(action);
|
|
56
|
+
const req = makeRequest(ACTION_URL + "&args=%5B%5D", "GET");
|
|
57
|
+
const result = await rscActionHandler(req, deps);
|
|
58
|
+
expect(result).toBe("data");
|
|
59
|
+
expect(action).toHaveBeenCalled();
|
|
60
|
+
});
|
|
61
|
+
it("defaults to POST for actions without .method property", async () => {
|
|
62
|
+
const action = vi.fn().mockReturnValue("ok");
|
|
63
|
+
const deps = createDeps(action);
|
|
64
|
+
const postReq = makeRequest(ACTION_URL, "POST", "[]");
|
|
65
|
+
const postResult = await rscActionHandler(postReq, deps);
|
|
66
|
+
expect(postResult).toBe("ok");
|
|
67
|
+
expect(action).toHaveBeenCalled();
|
|
68
|
+
});
|
|
69
|
+
it("rejects GET for actions without .method property", async () => {
|
|
70
|
+
const action = vi.fn();
|
|
71
|
+
const deps = createDeps(action);
|
|
72
|
+
const getReq = makeRequest(ACTION_URL, "GET");
|
|
73
|
+
const getResult = await rscActionHandler(getReq, deps);
|
|
74
|
+
expect(getResult).toBeInstanceOf(Response);
|
|
75
|
+
expect(getResult.status).toBe(405);
|
|
76
|
+
expect(action).not.toHaveBeenCalled();
|
|
77
|
+
});
|
|
78
|
+
it("includes allowed methods in 405 response body", async () => {
|
|
79
|
+
const action = Object.assign(vi.fn(), { method: "POST" });
|
|
80
|
+
const deps = createDeps(action);
|
|
81
|
+
const req = makeRequest(ACTION_URL, "GET");
|
|
82
|
+
const result = (await rscActionHandler(req, deps));
|
|
83
|
+
const body = await result.text();
|
|
84
|
+
expect(body).toContain("Method GET is not allowed");
|
|
85
|
+
expect(body).toContain("Allowed: POST");
|
|
86
|
+
});
|
|
87
|
+
it("rejects when .method is not a valid string", async () => {
|
|
88
|
+
const action = Object.assign(vi.fn(), {
|
|
89
|
+
method: 42,
|
|
90
|
+
});
|
|
91
|
+
const deps = createDeps(action);
|
|
92
|
+
const req = makeRequest(ACTION_URL, "GET");
|
|
93
|
+
const result = await rscActionHandler(req, deps);
|
|
94
|
+
expect(result).toBeInstanceOf(Response);
|
|
95
|
+
expect(result.status).toBe(405);
|
|
96
|
+
expect(action).not.toHaveBeenCalled();
|
|
97
|
+
});
|
|
98
|
+
it("throws when action is not a function", async () => {
|
|
99
|
+
const deps = {
|
|
100
|
+
getServerModuleExport: vi.fn().mockResolvedValue("not-a-function"),
|
|
101
|
+
decodeReply: vi.fn(),
|
|
102
|
+
};
|
|
103
|
+
const req = makeRequest(ACTION_URL, "GET");
|
|
104
|
+
await expect(rscActionHandler(req, deps)).rejects.toThrow("is not a function");
|
|
105
|
+
});
|
|
106
|
+
it("parses GET args from query string", async () => {
|
|
107
|
+
const action = Object.assign(vi.fn().mockReturnValue("result"), {
|
|
108
|
+
method: "GET",
|
|
109
|
+
});
|
|
110
|
+
const deps = createDeps(action);
|
|
111
|
+
const req = makeRequest(ACTION_URL + '&args=%5B%22hello%22%2C%2042%5D', "GET");
|
|
112
|
+
await rscActionHandler(req, deps);
|
|
113
|
+
expect(action).toHaveBeenCalledWith("hello", 42);
|
|
114
|
+
});
|
|
115
|
+
it("uses decodeReply for POST body", async () => {
|
|
116
|
+
const action = Object.assign(vi.fn().mockReturnValue("result"), {
|
|
117
|
+
method: "POST",
|
|
118
|
+
});
|
|
119
|
+
const deps = {
|
|
120
|
+
getServerModuleExport: vi.fn().mockResolvedValue(action),
|
|
121
|
+
decodeReply: vi.fn().mockResolvedValue(["decoded-arg"]),
|
|
122
|
+
};
|
|
123
|
+
const req = makeRequest(ACTION_URL, "POST", "serialized-body");
|
|
124
|
+
await rscActionHandler(req, deps);
|
|
125
|
+
expect(deps.decodeReply).toHaveBeenCalledWith("serialized-body", null);
|
|
126
|
+
expect(action).toHaveBeenCalledWith("decoded-arg");
|
|
127
|
+
});
|
|
128
|
+
});
|
|
@@ -2,6 +2,7 @@ import { isValidElementType } from "react-is";
|
|
|
2
2
|
import { registerClientReference as baseRegisterClientReference, registerServerReference as baseRegisterServerReference, decodeReply, } from "react-server-dom-webpack/server.edge";
|
|
3
3
|
import { getServerModuleExport } from "../imports/worker.js";
|
|
4
4
|
import { requestInfo } from "../requestInfo/worker.js";
|
|
5
|
+
import { rscActionHandler as rscActionHandlerImpl } from "./methodEnforcer.js";
|
|
5
6
|
export function registerServerReference(action, id, name) {
|
|
6
7
|
if (typeof action !== "function") {
|
|
7
8
|
return action;
|
|
@@ -48,28 +49,5 @@ export async function __smokeTestActionHandler(timestamp) {
|
|
|
48
49
|
return { status: "ok", timestamp };
|
|
49
50
|
}
|
|
50
51
|
export async function rscActionHandler(req) {
|
|
51
|
-
|
|
52
|
-
const contentType = req.headers.get("content-type");
|
|
53
|
-
let args = [];
|
|
54
|
-
if (req.method === "GET") {
|
|
55
|
-
const argsParam = url.searchParams.get("args");
|
|
56
|
-
if (argsParam) {
|
|
57
|
-
args = JSON.parse(argsParam);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
const data = contentType?.startsWith("multipart/form-data")
|
|
62
|
-
? await req.formData()
|
|
63
|
-
: await req.text();
|
|
64
|
-
args = (await decodeReply(data, null));
|
|
65
|
-
}
|
|
66
|
-
const actionId = url.searchParams.get("__rsc_action_id");
|
|
67
|
-
if (import.meta.env.VITE_IS_DEV_SERVER && actionId === "__rsc_hot_update") {
|
|
68
|
-
return null;
|
|
69
|
-
}
|
|
70
|
-
const action = await getServerModuleExport(actionId);
|
|
71
|
-
if (typeof action !== "function") {
|
|
72
|
-
throw new Error(`Action ${actionId} is not a function`);
|
|
73
|
-
}
|
|
74
|
-
return action(...args);
|
|
52
|
+
return rscActionHandlerImpl(req, { getServerModuleExport, decodeReply });
|
|
75
53
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rwsdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "Build fast, server-driven webapps on Cloudflare with SSR, RSC, and realtime",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -154,7 +154,7 @@
|
|
|
154
154
|
"license": "MIT",
|
|
155
155
|
"dependencies": {
|
|
156
156
|
"@ast-grep/napi": "~0.41.0",
|
|
157
|
-
"@cloudflare/workers-types": "~4.
|
|
157
|
+
"@cloudflare/workers-types": "~4.20260331.1",
|
|
158
158
|
"@mdx-js/mdx": "~3.1.1",
|
|
159
159
|
"@puppeteer/browsers": "~2.13.0",
|
|
160
160
|
"@types/decompress": "~4.2.7",
|
|
@@ -172,13 +172,13 @@
|
|
|
172
172
|
"execa": "~9.6.1",
|
|
173
173
|
"find-up": "~8.0.0",
|
|
174
174
|
"fs-extra": "~11.3.4",
|
|
175
|
-
"get-port": "^7.
|
|
175
|
+
"get-port": "^7.2.0",
|
|
176
176
|
"glob": "~13.0.6",
|
|
177
177
|
"ignore": "~7.0.5",
|
|
178
178
|
"jsonc-parser": "~3.3.1",
|
|
179
|
-
"kysely": "~0.28.
|
|
179
|
+
"kysely": "~0.28.15",
|
|
180
180
|
"kysely-do": "~0.0.1-rc.1",
|
|
181
|
-
"lodash": "~4.
|
|
181
|
+
"lodash": "~4.18.1",
|
|
182
182
|
"magic-string": "~0.30.21",
|
|
183
183
|
"picocolors": "~1.1.1",
|
|
184
184
|
"proper-lockfile": "~4.1.2",
|
|
@@ -199,13 +199,14 @@
|
|
|
199
199
|
"react-dom": ">=19.2.0-0 <19.3.0 || >=19.3.0-0 <20.0.0",
|
|
200
200
|
"react-server-dom-webpack": ">=19.2.0-0 <19.3.0 || >=19.3.0-0 <20.0.0",
|
|
201
201
|
"vite": "^6.2.6 || 7.x",
|
|
202
|
-
"wrangler": "^4.
|
|
202
|
+
"wrangler": "^4.77.0"
|
|
203
203
|
},
|
|
204
204
|
"packageManager": "pnpm@10.31.0",
|
|
205
205
|
"devDependencies": {
|
|
206
|
-
"@cloudflare/vite-plugin": "1.
|
|
206
|
+
"@cloudflare/vite-plugin": "1.30.1",
|
|
207
|
+
"wrangler": "^4.77.0",
|
|
207
208
|
"capnweb": "~0.5.0",
|
|
208
|
-
"@types/debug": "~4.1.
|
|
209
|
+
"@types/debug": "~4.1.13",
|
|
209
210
|
"@types/js-beautify": "~1.14.3",
|
|
210
211
|
"@types/lodash": "~4.17.24",
|
|
211
212
|
"@types/node": "~25.3.5",
|
|
@@ -213,8 +214,8 @@
|
|
|
213
214
|
"js-beautify": "~1.15.4",
|
|
214
215
|
"semver": "~7.7.4",
|
|
215
216
|
"tsx": "~4.21.0",
|
|
216
|
-
"typescript": "~
|
|
217
|
+
"typescript": "~6.0.2",
|
|
217
218
|
"vite": "~7.3.1",
|
|
218
|
-
"vitest": "~4.
|
|
219
|
+
"vitest": "~4.1.2"
|
|
219
220
|
}
|
|
220
221
|
}
|