rwsdk 1.0.0-beta.54 → 1.0.0-beta.56
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/lib/e2e/release.mjs +1 -1
- package/dist/runtime/client/client.js +29 -32
- package/dist/runtime/client/navigation.js +7 -0
- package/dist/runtime/client/navigation.test.js +53 -3
- package/dist/runtime/server.d.ts +4 -4
- package/dist/runtime/server.js +4 -8
- package/dist/vite/transformServerFunctions.test.mjs +30 -0
- package/package.json +33 -33
package/dist/lib/e2e/release.mjs
CHANGED
|
@@ -379,7 +379,7 @@ export async function runRelease(cwd, projectDir, resourceUniqueKey) {
|
|
|
379
379
|
const stdout = result.stdout;
|
|
380
380
|
// Extract deployment URL from output
|
|
381
381
|
log("Extracting deployment URL from output");
|
|
382
|
-
const urlMatch = stdout.match(/https:\/\/([a-zA-Z0-9-]+)
|
|
382
|
+
const urlMatch = stdout.match(/https:\/\/([a-zA-Z0-9-]+)(?:\.[a-zA-Z0-9-]+)?\.workers\.dev/);
|
|
383
383
|
if (!urlMatch || !urlMatch[0]) {
|
|
384
384
|
log("ERROR: Could not extract deployment URL from release output");
|
|
385
385
|
// Log more details about the output for debugging
|
|
@@ -64,22 +64,7 @@ export const fetchTransport = (transportContext) => {
|
|
|
64
64
|
});
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
|
-
|
|
68
|
-
if (transportContext.handleResponse) {
|
|
69
|
-
const response = await fetchPromise;
|
|
70
|
-
const shouldContinue = transportContext.handleResponse(response);
|
|
71
|
-
if (!shouldContinue) {
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
// Continue with the response if handler returned true
|
|
75
|
-
const streamData = createFromFetch(Promise.resolve(response), {
|
|
76
|
-
callServer: fetchCallServer,
|
|
77
|
-
});
|
|
78
|
-
if (source === "navigation" || source === "action") {
|
|
79
|
-
transportContext.setRscPayload(streamData);
|
|
80
|
-
}
|
|
81
|
-
const result = await streamData;
|
|
82
|
-
const rawActionResult = result.actionResult;
|
|
67
|
+
const processActionResponse = (rawActionResult) => {
|
|
83
68
|
if (isActionResponse(rawActionResult)) {
|
|
84
69
|
const actionResponse = rawActionResult.__rw_action_response;
|
|
85
70
|
const handledByHook = transportContext.onActionResponse?.(actionResponse) === true;
|
|
@@ -90,34 +75,46 @@ export const fetchTransport = (transportContext) => {
|
|
|
90
75
|
window.location.href = location;
|
|
91
76
|
return undefined;
|
|
92
77
|
}
|
|
78
|
+
if (actionResponse.status >= 400) {
|
|
79
|
+
throw new Error(`Server function returned status ${actionResponse.status}`);
|
|
80
|
+
}
|
|
93
81
|
}
|
|
94
82
|
return rawActionResult;
|
|
95
83
|
}
|
|
96
84
|
return rawActionResult;
|
|
85
|
+
};
|
|
86
|
+
// If there's a response handler, check the response first
|
|
87
|
+
if (transportContext.handleResponse) {
|
|
88
|
+
const response = await fetchPromise;
|
|
89
|
+
const shouldContinue = transportContext.handleResponse(response);
|
|
90
|
+
if (!shouldContinue) {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
// Continue with the response if handler returned true
|
|
94
|
+
const streamData = createFromFetch(Promise.resolve(response), {
|
|
95
|
+
callServer: fetchCallServer,
|
|
96
|
+
});
|
|
97
|
+
if (source === "navigation" || source === "action") {
|
|
98
|
+
transportContext.setRscPayload(streamData);
|
|
99
|
+
}
|
|
100
|
+
const result = await streamData;
|
|
101
|
+
return processActionResponse(result.actionResult);
|
|
97
102
|
}
|
|
98
103
|
// Original behavior when no handler is present
|
|
99
|
-
const
|
|
104
|
+
const response = await fetchPromise;
|
|
105
|
+
const location = response.headers.get("Location");
|
|
106
|
+
if (response.status >= 300 && response.status < 400 && location) {
|
|
107
|
+
window.location.href = location;
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
const streamData = createFromFetch(Promise.resolve(response), {
|
|
100
111
|
callServer: fetchCallServer,
|
|
101
112
|
});
|
|
102
113
|
if (source === "navigation" || source === "action") {
|
|
103
114
|
transportContext.setRscPayload(streamData);
|
|
104
115
|
}
|
|
105
116
|
const result = await streamData;
|
|
106
|
-
|
|
107
|
-
if (isActionResponse(rawActionResult)) {
|
|
108
|
-
const actionResponse = rawActionResult.__rw_action_response;
|
|
109
|
-
const handledByHook = transportContext.onActionResponse?.(actionResponse) === true;
|
|
110
|
-
if (!handledByHook) {
|
|
111
|
-
const location = actionResponse.headers["location"];
|
|
112
|
-
const isRedirect = actionResponse.status >= 300 && actionResponse.status < 400;
|
|
113
|
-
if (location && isRedirect) {
|
|
114
|
-
window.location.href = location;
|
|
115
|
-
return undefined;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
return rawActionResult;
|
|
119
|
-
}
|
|
120
|
-
return rawActionResult;
|
|
117
|
+
return processActionResponse(result.actionResult);
|
|
121
118
|
};
|
|
122
119
|
return fetchCallServer;
|
|
123
120
|
};
|
|
@@ -122,6 +122,13 @@ export function initClientNavigation(opts = {}) {
|
|
|
122
122
|
await globalThis.__rsc_callServer(null, null, "navigation");
|
|
123
123
|
});
|
|
124
124
|
function handleResponse(response) {
|
|
125
|
+
if (response.status >= 300 && response.status < 400) {
|
|
126
|
+
const location = response.headers.get("Location");
|
|
127
|
+
if (location) {
|
|
128
|
+
window.location.href = location;
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
125
132
|
if (!response.ok) {
|
|
126
133
|
// Redirect to the current page (window.location) to show the error
|
|
127
134
|
// This means the page that produced the error is called twice.
|
|
@@ -1,8 +1,31 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { validateClickEvent } from "./navigation";
|
|
1
|
+
import { describe, expect, it, vi, beforeEach } from "vitest";
|
|
2
|
+
import { validateClickEvent, initClientNavigation } from "./navigation";
|
|
3
|
+
// Mocking browser globals
|
|
4
|
+
vi.stubGlobal("window", {
|
|
5
|
+
location: { href: "http://localhost/" },
|
|
6
|
+
addEventListener: vi.fn(),
|
|
7
|
+
history: { scrollRestoration: "auto" },
|
|
8
|
+
});
|
|
9
|
+
vi.stubGlobal("document", {
|
|
10
|
+
addEventListener: vi.fn(),
|
|
11
|
+
});
|
|
12
|
+
vi.stubGlobal("history", {
|
|
13
|
+
scrollRestoration: "auto",
|
|
14
|
+
});
|
|
15
|
+
vi.stubGlobal("Headers", class {
|
|
16
|
+
constructor(init) {
|
|
17
|
+
this.map = {};
|
|
18
|
+
if (init && init.Location) {
|
|
19
|
+
this.map.location = init.Location;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
get(name) {
|
|
23
|
+
return this.map[name.toLowerCase()] || null;
|
|
24
|
+
}
|
|
25
|
+
});
|
|
3
26
|
describe("clientNavigation", () => {
|
|
4
27
|
let mockEvent = {
|
|
5
|
-
button: 0,
|
|
28
|
+
button: 0,
|
|
6
29
|
metaKey: false,
|
|
7
30
|
altKey: false,
|
|
8
31
|
shiftKey: false,
|
|
@@ -52,3 +75,30 @@ describe("clientNavigation", () => {
|
|
|
52
75
|
})).toBe(true);
|
|
53
76
|
});
|
|
54
77
|
});
|
|
78
|
+
describe("initClientNavigation", () => {
|
|
79
|
+
beforeEach(() => {
|
|
80
|
+
window.location.href = "http://localhost/";
|
|
81
|
+
vi.clearAllMocks();
|
|
82
|
+
});
|
|
83
|
+
it("handleResponse should follow redirects", () => {
|
|
84
|
+
const { handleResponse } = initClientNavigation();
|
|
85
|
+
const mockResponse = {
|
|
86
|
+
status: 302,
|
|
87
|
+
headers: new Headers({ Location: "/new-page" }),
|
|
88
|
+
ok: false,
|
|
89
|
+
};
|
|
90
|
+
const result = handleResponse(mockResponse);
|
|
91
|
+
expect(result).toBe(false);
|
|
92
|
+
expect(window.location.href).toBe("/new-page");
|
|
93
|
+
});
|
|
94
|
+
it("handleResponse should reload on error", () => {
|
|
95
|
+
const { handleResponse } = initClientNavigation();
|
|
96
|
+
const mockResponse = {
|
|
97
|
+
status: 500,
|
|
98
|
+
ok: false,
|
|
99
|
+
};
|
|
100
|
+
const result = handleResponse(mockResponse);
|
|
101
|
+
expect(result).toBe(false);
|
|
102
|
+
expect(window.location.href).toBe("http://localhost/");
|
|
103
|
+
});
|
|
104
|
+
});
|
package/dist/runtime/server.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
type Interruptor<TArgs extends any[] = any[]
|
|
1
|
+
type Interruptor<TArgs extends any[] = any[]> = (context: {
|
|
2
2
|
request: Request;
|
|
3
3
|
ctx: Record<string, any>;
|
|
4
4
|
args: TArgs;
|
|
5
|
-
}) => Promise<Response | void
|
|
5
|
+
}) => Promise<Response | void> | Response | void;
|
|
6
6
|
type ServerFunction<TArgs extends any[] = any[], TResult = any> = (...args: TArgs) => Promise<TResult>;
|
|
7
7
|
type ServerFunctionOptions = {
|
|
8
8
|
method?: "GET" | "POST";
|
|
@@ -29,7 +29,7 @@ type WrappedServerFunction<TArgs extends any[] = any[], TResult = any> = {
|
|
|
29
29
|
* })
|
|
30
30
|
* ```
|
|
31
31
|
*/
|
|
32
|
-
export declare function serverQuery<TArgs extends any[]
|
|
32
|
+
export declare function serverQuery<TArgs extends any[], TResult>(fnsOrFn: ServerFunction<TArgs, TResult> | [...Interruptor<TArgs>[], ServerFunction<TArgs, TResult>], options?: ServerFunctionOptions): WrappedServerFunction<TArgs, TResult>;
|
|
33
33
|
/**
|
|
34
34
|
* Wrap a function to be used as a server action.
|
|
35
35
|
*
|
|
@@ -48,5 +48,5 @@ export declare function serverQuery<TArgs extends any[] = any[], TResult = any>(
|
|
|
48
48
|
* })
|
|
49
49
|
* ```
|
|
50
50
|
*/
|
|
51
|
-
export declare function serverAction<TArgs extends any[]
|
|
51
|
+
export declare function serverAction<TArgs extends any[], TResult>(fnsOrFn: ServerFunction<TArgs, TResult> | [...Interruptor<TArgs>[], ServerFunction<TArgs, TResult>], options?: ServerFunctionOptions): WrappedServerFunction<TArgs, TResult>;
|
|
52
52
|
export {};
|
package/dist/runtime/server.js
CHANGED
|
@@ -6,18 +6,14 @@ function createServerFunction(fns, mainFn, options) {
|
|
|
6
6
|
for (const fn of fns) {
|
|
7
7
|
const result = await fn({ request, ctx, args });
|
|
8
8
|
if (result instanceof Response) {
|
|
9
|
-
// We
|
|
10
|
-
//
|
|
11
|
-
|
|
12
|
-
// In the RSC context, throwing a Response is a common pattern to short-circuit.
|
|
13
|
-
throw result;
|
|
9
|
+
// We return the Response so it can be handled by the action handler
|
|
10
|
+
// and serialized into the RSC stream via normalizeActionResult.
|
|
11
|
+
return result;
|
|
14
12
|
}
|
|
15
13
|
}
|
|
16
14
|
return mainFn(...args);
|
|
17
15
|
};
|
|
18
|
-
wrapped.method = options?.method ?? "POST";
|
|
19
|
-
// User said: "export const getProject = serverQuery(...) // Defaults to GET"
|
|
20
|
-
// So serverQuery defaults to GET, serverAction defaults to POST?
|
|
16
|
+
wrapped.method = options?.method ?? "POST";
|
|
21
17
|
return wrapped;
|
|
22
18
|
}
|
|
23
19
|
/**
|
|
@@ -119,6 +119,33 @@ export default serverQuery(async (id) => {
|
|
|
119
119
|
export default serverAction(async (id) => {
|
|
120
120
|
return { id, name: "Project X" };
|
|
121
121
|
});
|
|
122
|
+
`;
|
|
123
|
+
let SERVER_QUERY_ARRAY_CODE = `
|
|
124
|
+
"use server";
|
|
125
|
+
export const getProject = serverQuery([
|
|
126
|
+
auth,
|
|
127
|
+
async (id) => {
|
|
128
|
+
return { id, name: "Project X" };
|
|
129
|
+
}
|
|
130
|
+
]);
|
|
131
|
+
`;
|
|
132
|
+
let SERVER_ACTION_ARRAY_CODE = `
|
|
133
|
+
"use server";
|
|
134
|
+
export const upvote = serverAction([
|
|
135
|
+
auth,
|
|
136
|
+
async (id) => {
|
|
137
|
+
return { id, count: 1 };
|
|
138
|
+
}
|
|
139
|
+
]);
|
|
140
|
+
`;
|
|
141
|
+
let SERVER_QUERY_ARRAY_POST_CODE = `
|
|
142
|
+
"use server";
|
|
143
|
+
export const getProject = serverQuery([
|
|
144
|
+
auth,
|
|
145
|
+
async (id) => {
|
|
146
|
+
return { id, name: "Project X" };
|
|
147
|
+
}
|
|
148
|
+
], { method: "POST" });
|
|
122
149
|
`;
|
|
123
150
|
const TEST_CASES = {
|
|
124
151
|
COMMENT_CODE,
|
|
@@ -137,6 +164,9 @@ export default serverAction(async (id) => {
|
|
|
137
164
|
SERVER_ACTION_CODE,
|
|
138
165
|
SERVER_QUERY_DEFAULT_CODE,
|
|
139
166
|
SERVER_ACTION_DEFAULT_CODE,
|
|
167
|
+
SERVER_QUERY_ARRAY_CODE,
|
|
168
|
+
SERVER_ACTION_ARRAY_CODE,
|
|
169
|
+
SERVER_QUERY_ARRAY_POST_CODE,
|
|
140
170
|
};
|
|
141
171
|
describe("TRANSFORMS", () => {
|
|
142
172
|
for (const [key, CODE] of Object.entries(TEST_CASES)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rwsdk",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.56",
|
|
4
4
|
"description": "Build fast, server-driven webapps on Cloudflare with SSR, RSC, and realtime",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -153,68 +153,68 @@
|
|
|
153
153
|
"author": "RedwoodSDK <peter@redwoodjs.com>",
|
|
154
154
|
"license": "MIT",
|
|
155
155
|
"dependencies": {
|
|
156
|
-
"@ast-grep/napi": "~0.
|
|
157
|
-
"@cloudflare/workers-types": "~4.
|
|
156
|
+
"@ast-grep/napi": "~0.41.0",
|
|
157
|
+
"@cloudflare/workers-types": "~4.20260305.1",
|
|
158
158
|
"@mdx-js/mdx": "~3.1.1",
|
|
159
|
-
"@puppeteer/browsers": "~2.
|
|
159
|
+
"@puppeteer/browsers": "~2.13.0",
|
|
160
160
|
"@types/decompress": "~4.2.7",
|
|
161
161
|
"@types/fs-extra": "~11.0.4",
|
|
162
|
-
"@types/glob": "^
|
|
162
|
+
"@types/glob": "^9.0.0",
|
|
163
163
|
"@types/react": "~19.2.14",
|
|
164
164
|
"@types/react-dom": "~19.2.3",
|
|
165
|
-
"@types/react-is": "~19.
|
|
166
|
-
"@vitejs/plugin-react": "~5.
|
|
167
|
-
"chokidar": "~
|
|
168
|
-
"debug": "~4.4.
|
|
165
|
+
"@types/react-is": "~19.2.0",
|
|
166
|
+
"@vitejs/plugin-react": "~5.1.4",
|
|
167
|
+
"chokidar": "~5.0.0",
|
|
168
|
+
"debug": "~4.4.3",
|
|
169
169
|
"decompress": "~4.2.1",
|
|
170
|
-
"enhanced-resolve": "~5.
|
|
171
|
-
"eventsource-parser": "~3.0.
|
|
172
|
-
"execa": "~9.6.
|
|
170
|
+
"enhanced-resolve": "~5.20.0",
|
|
171
|
+
"eventsource-parser": "~3.0.6",
|
|
172
|
+
"execa": "~9.6.1",
|
|
173
173
|
"find-up": "~8.0.0",
|
|
174
|
-
"fs-extra": "~11.3.
|
|
174
|
+
"fs-extra": "~11.3.4",
|
|
175
175
|
"get-port": "^7.1.0",
|
|
176
|
-
"glob": "~
|
|
177
|
-
"ignore": "~7.0.
|
|
176
|
+
"glob": "~13.0.6",
|
|
177
|
+
"ignore": "~7.0.5",
|
|
178
178
|
"jsonc-parser": "~3.3.1",
|
|
179
|
-
"kysely": "~0.28.
|
|
179
|
+
"kysely": "~0.28.11",
|
|
180
180
|
"kysely-do": "~0.0.1-rc.1",
|
|
181
181
|
"lodash": "~4.17.23",
|
|
182
|
-
"magic-string": "~0.30.
|
|
182
|
+
"magic-string": "~0.30.21",
|
|
183
183
|
"picocolors": "~1.1.1",
|
|
184
184
|
"proper-lockfile": "~4.1.2",
|
|
185
|
-
"puppeteer-core": "~24.
|
|
186
|
-
"react-is": "~19.
|
|
187
|
-
"rsc-html-stream": "~0.0.
|
|
185
|
+
"puppeteer-core": "~24.38.0",
|
|
186
|
+
"react-is": "~19.2.4",
|
|
187
|
+
"rsc-html-stream": "~0.0.7",
|
|
188
188
|
"server-only": "^0.0.1",
|
|
189
189
|
"tmp-promise": "~3.0.3",
|
|
190
|
-
"ts-morph": "~27.0.
|
|
190
|
+
"ts-morph": "~27.0.2",
|
|
191
191
|
"unique-names-generator": "~4.7.1",
|
|
192
|
-
"vibe-rules": "~0.3.
|
|
193
|
-
"vite-tsconfig-paths": "~
|
|
192
|
+
"vibe-rules": "~0.3.91",
|
|
193
|
+
"vite-tsconfig-paths": "~6.1.1"
|
|
194
194
|
},
|
|
195
195
|
"peerDependencies": {
|
|
196
|
-
"@cloudflare/vite-plugin": "^1.
|
|
197
|
-
"capnweb": "~0.
|
|
196
|
+
"@cloudflare/vite-plugin": "^1.26.0",
|
|
197
|
+
"capnweb": "~0.5.0",
|
|
198
198
|
"react": ">=19.2.0-0 <19.3.0 || >=19.3.0-0 <20.0.0",
|
|
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.70.0"
|
|
203
203
|
},
|
|
204
204
|
"packageManager": "pnpm@10.28.2",
|
|
205
205
|
"devDependencies": {
|
|
206
|
-
"@cloudflare/vite-plugin": "1.
|
|
207
|
-
"capnweb": "~0.
|
|
206
|
+
"@cloudflare/vite-plugin": "1.26.0",
|
|
207
|
+
"capnweb": "~0.5.0",
|
|
208
208
|
"@types/debug": "~4.1.12",
|
|
209
209
|
"@types/js-beautify": "~1.14.3",
|
|
210
|
-
"@types/lodash": "~4.17.
|
|
211
|
-
"@types/node": "~
|
|
210
|
+
"@types/lodash": "~4.17.24",
|
|
211
|
+
"@types/node": "~25.3.3",
|
|
212
212
|
"@types/proper-lockfile": "~4.1.4",
|
|
213
213
|
"js-beautify": "~1.15.4",
|
|
214
|
-
"semver": "~7.7.
|
|
214
|
+
"semver": "~7.7.4",
|
|
215
215
|
"tsx": "~4.21.0",
|
|
216
|
-
"typescript": "~5.9.
|
|
216
|
+
"typescript": "~5.9.3",
|
|
217
217
|
"vite": "~7.3.1",
|
|
218
|
-
"vitest": "~
|
|
218
|
+
"vitest": "~4.0.18"
|
|
219
219
|
}
|
|
220
220
|
}
|