webstudio 0.304.0 → 0.306.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.
- package/lib/cli.js +7259 -2343
- package/lib/content-runtime.js +2 -2
- package/package.json +24 -24
- package/templates/cloudflare/package.json +1 -1
- package/templates/defaults/app/route-templates/html.tsx +79 -13
- package/templates/defaults/app/route-templates/text.tsx +2 -2
- package/templates/defaults/app/route-templates/xml.tsx +2 -2
- package/templates/defaults/package.json +8 -8
- package/templates/react-router/app/route-templates/html.tsx +87 -35
- package/templates/react-router/app/route-templates/text.tsx +8 -22
- package/templates/react-router/app/route-templates/xml.tsx +8 -22
- package/templates/react-router/package.json +8 -8
- package/templates/react-router/vite.config.ts +15 -1
- package/templates/react-router-cloudflare/package.json +1 -1
- package/templates/ssg/app/route-templates/dynamic/+onBeforePrerenderStart.ts.template +1 -0
- package/templates/ssg/app/route-templates/{html → shared}/+data.ts +2 -2
- package/templates/ssg/app/route-templates/text/+config.ts +5 -0
- package/templates/ssg/app/route-templates/text/+onRenderHtml.ts +5 -0
- package/templates/ssg/app/route-templates/text/+route.ts.template +1 -0
- package/templates/ssg/package.json +10 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webstudio",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.306.0",
|
|
4
4
|
"description": "Webstudio CLI",
|
|
5
5
|
"author": "Webstudio <github@webstudio.is>",
|
|
6
6
|
"homepage": "https://webstudio.is",
|
|
@@ -53,10 +53,10 @@
|
|
|
53
53
|
"which": "^5.0.0",
|
|
54
54
|
"yargs": "^17.7.2",
|
|
55
55
|
"zod": "^4.4.3",
|
|
56
|
-
"@webstudio-is/
|
|
57
|
-
"@webstudio-is/
|
|
58
|
-
"@webstudio-is/
|
|
59
|
-
"@webstudio-is/
|
|
56
|
+
"@webstudio-is/project-migrations": "0.306.0",
|
|
57
|
+
"@webstudio-is/http-client": "0.306.0",
|
|
58
|
+
"@webstudio-is/protocol": "0.306.0",
|
|
59
|
+
"@webstudio-is/sync-client": "0.0.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@cloudflare/vite-plugin": "^1.1.0",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"@types/which": "^3.0.4",
|
|
81
81
|
"@types/yargs": "^17.0.33",
|
|
82
82
|
"@vercel/react-router": "^1.1.0",
|
|
83
|
-
"@vitejs/plugin-react": "^4.
|
|
83
|
+
"@vitejs/plugin-react": "^4.7.0",
|
|
84
84
|
"h3": "^1.15.1",
|
|
85
85
|
"ipx": "^3.0.3",
|
|
86
86
|
"isbot": "^5.1.25",
|
|
@@ -95,28 +95,28 @@
|
|
|
95
95
|
"shiki": "4.4.1",
|
|
96
96
|
"ts-expect": "^1.3.0",
|
|
97
97
|
"typescript": "7.0.2",
|
|
98
|
-
"vike": "
|
|
99
|
-
"vite": "
|
|
98
|
+
"vike": "0.4.267-commit-feffb0f",
|
|
99
|
+
"vite": "7.1.12",
|
|
100
100
|
"vitest": "^3.1.2",
|
|
101
101
|
"wrangler": "4.130.0",
|
|
102
|
-
"@webstudio-is/css-engine": "0.
|
|
103
|
-
"@webstudio-is/
|
|
104
|
-
"@webstudio-is/
|
|
105
|
-
"@webstudio-is/fonts": "0.
|
|
106
|
-
"@webstudio-is/image": "0.
|
|
102
|
+
"@webstudio-is/css-engine": "0.306.0",
|
|
103
|
+
"@webstudio-is/content-engine": "0.306.0",
|
|
104
|
+
"@webstudio-is/expression": "0.306.0",
|
|
105
|
+
"@webstudio-is/fonts": "0.306.0",
|
|
106
|
+
"@webstudio-is/image": "0.306.0",
|
|
107
|
+
"@webstudio-is/react-sdk": "0.306.0",
|
|
108
|
+
"@webstudio-is/query-builder": "0.306.0",
|
|
109
|
+
"@webstudio-is/sdk": "0.306.0",
|
|
107
110
|
"@webstudio-is/project-build": "0.0.0",
|
|
108
|
-
"@webstudio-is/
|
|
109
|
-
"@webstudio-is/sdk-components-
|
|
110
|
-
"@webstudio-is/sdk-components-react-
|
|
111
|
-
"@webstudio-is/sdk-components-
|
|
112
|
-
"@webstudio-is/sdk-components-react-router": "0.304.0",
|
|
113
|
-
"@webstudio-is/vision": "0.0.0",
|
|
114
|
-
"@webstudio-is/sdk-components-animation": "0.304.0",
|
|
115
|
-
"@webstudio-is/sdk-components-registry": "0.304.0",
|
|
111
|
+
"@webstudio-is/sdk-components-react": "0.306.0",
|
|
112
|
+
"@webstudio-is/sdk-components-animation": "0.306.0",
|
|
113
|
+
"@webstudio-is/sdk-components-react-radix": "0.306.0",
|
|
114
|
+
"@webstudio-is/sdk-components-registry": "0.306.0",
|
|
116
115
|
"@webstudio-is/tsconfig": "1.0.7",
|
|
117
|
-
"@webstudio-is/react-
|
|
118
|
-
"@webstudio-is/sdk": "0.
|
|
119
|
-
"@webstudio-is/wsauth": "0.
|
|
116
|
+
"@webstudio-is/sdk-components-react-remix": "0.306.0",
|
|
117
|
+
"@webstudio-is/sdk-components-react-router": "0.306.0",
|
|
118
|
+
"@webstudio-is/wsauth": "0.306.0",
|
|
119
|
+
"@webstudio-is/vision": "0.0.0"
|
|
120
120
|
},
|
|
121
121
|
"scripts": {
|
|
122
122
|
"typecheck": "tsc --noEmit",
|
|
@@ -12,12 +12,24 @@ import {
|
|
|
12
12
|
import { useLoaderData } from "@remix-run/react";
|
|
13
13
|
import {
|
|
14
14
|
isLocalResource,
|
|
15
|
-
loadResource,
|
|
16
15
|
loadResources,
|
|
16
|
+
loadResourceWithEmail,
|
|
17
|
+
loadResourcesWithEmail,
|
|
17
18
|
cachedFetch,
|
|
19
|
+
getSystemSearch,
|
|
20
|
+
} from "@webstudio-is/sdk/runtime";
|
|
21
|
+
import {
|
|
22
|
+
handleManagedFormSubmission,
|
|
23
|
+
getManagedFormFailure,
|
|
24
|
+
readFormDataWithLimit,
|
|
25
|
+
type ManagedFormResponse,
|
|
26
|
+
} from "@webstudio-is/sdk/form/server";
|
|
27
|
+
import {
|
|
28
|
+
managedFormRequestParamName,
|
|
18
29
|
formIdFieldName,
|
|
30
|
+
managedFormIdFieldName,
|
|
19
31
|
formBotFieldName,
|
|
20
|
-
} from "@webstudio-is/sdk/
|
|
32
|
+
} from "@webstudio-is/sdk/form";
|
|
21
33
|
import { authenticateRequest } from "@webstudio-is/wsauth";
|
|
22
34
|
import {
|
|
23
35
|
ReactSdkContext,
|
|
@@ -37,6 +49,8 @@ import {
|
|
|
37
49
|
} from "__CLIENT__";
|
|
38
50
|
import {
|
|
39
51
|
getResources,
|
|
52
|
+
getManagedFormSubmissions,
|
|
53
|
+
getManagedFormResourceGraph,
|
|
40
54
|
getPageMeta,
|
|
41
55
|
getRemixParams,
|
|
42
56
|
contactEmail,
|
|
@@ -46,6 +60,11 @@ import css from "__CSS__?url";
|
|
|
46
60
|
import { sitemap } from "__SITEMAP__";
|
|
47
61
|
import { authRoutes } from "__AUTH__";
|
|
48
62
|
import { createGeneratedAssetResourceFetch } from "__ASSET_QUERY_RUNTIME__";
|
|
63
|
+
import {
|
|
64
|
+
createManagedFormEmailSender,
|
|
65
|
+
createManagedFormResourceFetch,
|
|
66
|
+
validateManagedFormEmail,
|
|
67
|
+
} from "__MANAGED_FORM_FETCH__";
|
|
49
68
|
import { assetUrlsByPath } from "__ASSETS__";
|
|
50
69
|
|
|
51
70
|
const authenticateProductionRequest = (request: Request) => {
|
|
@@ -113,7 +132,7 @@ export const loader = async (arg: LoaderFunctionArgs) => {
|
|
|
113
132
|
const params = getRemixParams(arg.params);
|
|
114
133
|
const system = {
|
|
115
134
|
params,
|
|
116
|
-
|
|
135
|
+
...getSystemSearch(url.searchParams),
|
|
117
136
|
origin: url.origin,
|
|
118
137
|
pathname: url.pathname,
|
|
119
138
|
};
|
|
@@ -257,24 +276,66 @@ const getRequestHost = (request: Request): string =>
|
|
|
257
276
|
export const action = async ({
|
|
258
277
|
request,
|
|
259
278
|
context,
|
|
279
|
+
params,
|
|
260
280
|
}: ActionFunctionArgs): Promise<
|
|
261
|
-
{ success: true } | { success: false; errors: string[] }
|
|
281
|
+
{ success: true } | { success: false; errors: string[] } | ManagedFormResponse
|
|
262
282
|
> => {
|
|
263
283
|
authenticateProductionRequest(request);
|
|
264
284
|
|
|
285
|
+
let isManagedFormRequest = false;
|
|
265
286
|
try {
|
|
266
287
|
const url = new URL(request.url);
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
288
|
+
isManagedFormRequest =
|
|
289
|
+
url.searchParams.get(managedFormRequestParamName) === "1";
|
|
290
|
+
url.searchParams.delete(managedFormRequestParamName);
|
|
291
|
+
if (!isManagedFormRequest) {
|
|
292
|
+
url.host = getRequestHost(request);
|
|
293
|
+
}
|
|
294
|
+
const formData = isManagedFormRequest
|
|
295
|
+
? await readFormDataWithLimit(request)
|
|
296
|
+
: await request.formData();
|
|
270
297
|
|
|
271
298
|
const system = {
|
|
272
|
-
params: {},
|
|
273
|
-
|
|
299
|
+
params: getRemixParams(params ?? {}),
|
|
300
|
+
...getSystemSearch(url.searchParams),
|
|
274
301
|
origin: url.origin,
|
|
275
302
|
pathname: url.pathname,
|
|
276
303
|
};
|
|
277
304
|
|
|
305
|
+
const managedFormIds = formData.getAll(managedFormIdFieldName);
|
|
306
|
+
if (!isManagedFormRequest && managedFormIds.length > 0) {
|
|
307
|
+
throw new Error("Invalid Form submission");
|
|
308
|
+
}
|
|
309
|
+
if (isManagedFormRequest) {
|
|
310
|
+
if (managedFormIds.length !== 1 || formData.has(formIdFieldName)) {
|
|
311
|
+
throw new Error("Invalid Form submission");
|
|
312
|
+
}
|
|
313
|
+
const protectedFetch = createManagedFormResourceFetch({
|
|
314
|
+
request,
|
|
315
|
+
context,
|
|
316
|
+
projectDomain,
|
|
317
|
+
});
|
|
318
|
+
return await handleManagedFormSubmission({
|
|
319
|
+
request,
|
|
320
|
+
formData,
|
|
321
|
+
url,
|
|
322
|
+
system,
|
|
323
|
+
configuration: (id) => getManagedFormSubmissions().get(id),
|
|
324
|
+
getGraph: (id, values) => getManagedFormResourceGraph(id, values),
|
|
325
|
+
createEmailSender: (data) =>
|
|
326
|
+
createManagedFormEmailSender({ context, formData: data, projectId }),
|
|
327
|
+
validateEmail: validateManagedFormEmail,
|
|
328
|
+
resourceFetch: protectedFetch,
|
|
329
|
+
validateDestination: protectedFetch.validateDestination,
|
|
330
|
+
trustedIp:
|
|
331
|
+
typeof context === "object" &&
|
|
332
|
+
context !== null &&
|
|
333
|
+
"cloudflare" in context
|
|
334
|
+
? request.headers.get("cf-connecting-ip") ?? undefined
|
|
335
|
+
: undefined,
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
|
|
278
339
|
const resourceName = formData.get(formIdFieldName);
|
|
279
340
|
const generatedResources = getResources({ system });
|
|
280
341
|
const actionResource =
|
|
@@ -308,7 +369,7 @@ export const action = async ({
|
|
|
308
369
|
formData.delete(formIdFieldName);
|
|
309
370
|
formData.delete(formBotFieldName);
|
|
310
371
|
|
|
311
|
-
let result: Awaited<ReturnType<typeof
|
|
372
|
+
let result: Awaited<ReturnType<typeof loadResourceWithEmail>>;
|
|
312
373
|
if (actionResource === undefined) {
|
|
313
374
|
if (contactEmail === undefined) {
|
|
314
375
|
throw new Error("Contact email not found");
|
|
@@ -322,14 +383,14 @@ export const action = async ({
|
|
|
322
383
|
if (resource === undefined) {
|
|
323
384
|
throw Error("Resource not found");
|
|
324
385
|
}
|
|
325
|
-
result = await
|
|
386
|
+
result = await loadResourceWithEmail(fetch, resource);
|
|
326
387
|
} else {
|
|
327
388
|
const actionFetch = await createGeneratedAssetResourceFetch({
|
|
328
389
|
request,
|
|
329
390
|
context,
|
|
330
391
|
fallback: customFetch,
|
|
331
392
|
});
|
|
332
|
-
const results = await
|
|
393
|
+
const results = await loadResourcesWithEmail(
|
|
333
394
|
actionFetch,
|
|
334
395
|
{
|
|
335
396
|
...generatedResources.data,
|
|
@@ -348,7 +409,7 @@ export const action = async ({
|
|
|
348
409
|
if (actionResult === undefined) {
|
|
349
410
|
throw Error("Resource not found");
|
|
350
411
|
}
|
|
351
|
-
result = actionResult as Awaited<ReturnType<typeof
|
|
412
|
+
result = actionResult as Awaited<ReturnType<typeof loadResourceWithEmail>>;
|
|
352
413
|
}
|
|
353
414
|
const { ok, statusText } = result;
|
|
354
415
|
if (ok) {
|
|
@@ -358,6 +419,11 @@ export const action = async ({
|
|
|
358
419
|
} catch (error) {
|
|
359
420
|
console.error(error);
|
|
360
421
|
|
|
422
|
+
if (isManagedFormRequest) {
|
|
423
|
+
return getManagedFormFailure(
|
|
424
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
425
|
+
);
|
|
426
|
+
}
|
|
361
427
|
return {
|
|
362
428
|
success: false,
|
|
363
429
|
errors: [error instanceof Error ? error.message : "Unknown error"],
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type LoaderFunctionArgs, redirect } from "@remix-run/server-runtime";
|
|
2
|
-
import { isLocalResource, loadResources } from "@webstudio-is/sdk/runtime";
|
|
2
|
+
import { isLocalResource, loadResources, getSystemSearch } from "@webstudio-is/sdk/runtime";
|
|
3
3
|
import { authenticateRequest } from "@webstudio-is/wsauth";
|
|
4
4
|
import { projectDomain } from "__CLIENT__";
|
|
5
5
|
import { getPageMeta, getRemixParams, getResources } from "__SERVER__";
|
|
@@ -71,7 +71,7 @@ export const loader = async (arg: LoaderFunctionArgs) => {
|
|
|
71
71
|
|
|
72
72
|
const system = {
|
|
73
73
|
params,
|
|
74
|
-
|
|
74
|
+
...getSystemSearch(url.searchParams),
|
|
75
75
|
origin: url.origin,
|
|
76
76
|
pathname: url.pathname,
|
|
77
77
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { renderToString } from "react-dom/server";
|
|
2
2
|
import { type LoaderFunctionArgs, redirect } from "@remix-run/server-runtime";
|
|
3
|
-
import { isLocalResource, loadResources } from "@webstudio-is/sdk/runtime";
|
|
3
|
+
import { isLocalResource, loadResources, getSystemSearch } from "@webstudio-is/sdk/runtime";
|
|
4
4
|
import { authenticateRequest } from "@webstudio-is/wsauth";
|
|
5
5
|
import {
|
|
6
6
|
ReactSdkContext,
|
|
@@ -79,7 +79,7 @@ export const loader = async (arg: LoaderFunctionArgs) => {
|
|
|
79
79
|
|
|
80
80
|
const system = {
|
|
81
81
|
params,
|
|
82
|
-
|
|
82
|
+
...getSystemSearch(url.searchParams),
|
|
83
83
|
origin: url.origin,
|
|
84
84
|
pathname: url.pathname,
|
|
85
85
|
};
|
|
@@ -13,14 +13,14 @@
|
|
|
13
13
|
"@remix-run/node": "2.16.5",
|
|
14
14
|
"@remix-run/react": "2.16.5",
|
|
15
15
|
"@remix-run/server-runtime": "2.16.5",
|
|
16
|
-
"@webstudio-is/image": "0.
|
|
17
|
-
"@webstudio-is/react-sdk": "0.
|
|
18
|
-
"@webstudio-is/sdk": "0.
|
|
19
|
-
"@webstudio-is/sdk-components-react": "0.
|
|
20
|
-
"@webstudio-is/sdk-components-animation": "0.
|
|
21
|
-
"@webstudio-is/sdk-components-react-radix": "0.
|
|
22
|
-
"@webstudio-is/sdk-components-react-remix": "0.
|
|
23
|
-
"@webstudio-is/wsauth": "0.
|
|
16
|
+
"@webstudio-is/image": "0.306.0",
|
|
17
|
+
"@webstudio-is/react-sdk": "0.306.0",
|
|
18
|
+
"@webstudio-is/sdk": "0.306.0",
|
|
19
|
+
"@webstudio-is/sdk-components-react": "0.306.0",
|
|
20
|
+
"@webstudio-is/sdk-components-animation": "0.306.0",
|
|
21
|
+
"@webstudio-is/sdk-components-react-radix": "0.306.0",
|
|
22
|
+
"@webstudio-is/sdk-components-react-remix": "0.306.0",
|
|
23
|
+
"@webstudio-is/wsauth": "0.306.0",
|
|
24
24
|
"isbot": "^5.1.25",
|
|
25
25
|
"react": "18.3.0-canary-14898b6a9-20240318",
|
|
26
26
|
"react-dom": "18.3.0-canary-14898b6a9-20240318",
|
|
@@ -12,13 +12,25 @@ import {
|
|
|
12
12
|
} from "react-router";
|
|
13
13
|
import {
|
|
14
14
|
isLocalResource,
|
|
15
|
-
loadResource,
|
|
16
15
|
loadResources,
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
loadResourceWithEmail,
|
|
17
|
+
loadResourcesWithEmail,
|
|
18
|
+
getSystemSearch,
|
|
19
19
|
cachedFetch,
|
|
20
20
|
} from "@webstudio-is/sdk/runtime";
|
|
21
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
handleManagedFormSubmission,
|
|
23
|
+
getManagedFormFailure,
|
|
24
|
+
readFormDataWithLimit,
|
|
25
|
+
type ManagedFormResponse,
|
|
26
|
+
} from "@webstudio-is/sdk/form/server";
|
|
27
|
+
import {
|
|
28
|
+
managedFormRequestParamName,
|
|
29
|
+
formIdFieldName,
|
|
30
|
+
managedFormIdFieldName,
|
|
31
|
+
formBotFieldName,
|
|
32
|
+
} from "@webstudio-is/sdk/form";
|
|
33
|
+
import { authenticateProjectRequest } from "@webstudio-is/wsauth";
|
|
22
34
|
import {
|
|
23
35
|
ReactSdkContext,
|
|
24
36
|
PageSettingsMeta,
|
|
@@ -36,6 +48,8 @@ import {
|
|
|
36
48
|
} from "__CLIENT__";
|
|
37
49
|
import {
|
|
38
50
|
getResources,
|
|
51
|
+
getManagedFormSubmissions,
|
|
52
|
+
getManagedFormResourceGraph,
|
|
39
53
|
getPageMeta,
|
|
40
54
|
getRemixParams,
|
|
41
55
|
contactEmail,
|
|
@@ -45,26 +59,13 @@ import css from "__CSS__?url";
|
|
|
45
59
|
import { sitemap } from "__SITEMAP__";
|
|
46
60
|
import { authRoutes } from "__AUTH__";
|
|
47
61
|
import { createGeneratedAssetResourceFetch } from "__ASSET_QUERY_RUNTIME__";
|
|
62
|
+
import {
|
|
63
|
+
createManagedFormEmailSender,
|
|
64
|
+
createManagedFormResourceFetch,
|
|
65
|
+
validateManagedFormEmail,
|
|
66
|
+
} from "__MANAGED_FORM_FETCH__";
|
|
48
67
|
import { assetUrlsByPath } from "__ASSETS__";
|
|
49
68
|
|
|
50
|
-
const authenticateProductionRequest = (request: Request) => {
|
|
51
|
-
const host =
|
|
52
|
-
request.headers.get("x-forwarded-host") ||
|
|
53
|
-
request.headers.get("host") ||
|
|
54
|
-
"";
|
|
55
|
-
|
|
56
|
-
const requestHost = host.split(":")[0];
|
|
57
|
-
if (
|
|
58
|
-
projectDomain !== undefined &&
|
|
59
|
-
(requestHost === projectDomain ||
|
|
60
|
-
requestHost.startsWith(`${projectDomain}.`))
|
|
61
|
-
) {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return authenticateRequest(request, authRoutes);
|
|
66
|
-
};
|
|
67
|
-
|
|
68
69
|
const customFetch: typeof fetch = (input, init) => {
|
|
69
70
|
if (typeof input !== "string") {
|
|
70
71
|
return cachedFetch(projectId, input, init);
|
|
@@ -99,7 +100,11 @@ const customFetch: typeof fetch = (input, init) => {
|
|
|
99
100
|
};
|
|
100
101
|
|
|
101
102
|
export const loader = async (arg: LoaderFunctionArgs) => {
|
|
102
|
-
const authRoute =
|
|
103
|
+
const authRoute = authenticateProjectRequest(
|
|
104
|
+
arg.request,
|
|
105
|
+
authRoutes,
|
|
106
|
+
projectDomain
|
|
107
|
+
);
|
|
103
108
|
|
|
104
109
|
const url = new URL(arg.request.url);
|
|
105
110
|
const host =
|
|
@@ -112,7 +117,7 @@ export const loader = async (arg: LoaderFunctionArgs) => {
|
|
|
112
117
|
const params = getRemixParams(arg.params);
|
|
113
118
|
const system = {
|
|
114
119
|
params,
|
|
115
|
-
|
|
120
|
+
...getSystemSearch(url.searchParams),
|
|
116
121
|
origin: url.origin,
|
|
117
122
|
pathname: url.pathname,
|
|
118
123
|
};
|
|
@@ -256,24 +261,66 @@ const getRequestHost = (request: Request): string =>
|
|
|
256
261
|
export const action = async ({
|
|
257
262
|
request,
|
|
258
263
|
context,
|
|
264
|
+
params,
|
|
259
265
|
}: ActionFunctionArgs): Promise<
|
|
260
|
-
{ success: true } | { success: false; errors: string[] }
|
|
266
|
+
{ success: true } | { success: false; errors: string[] } | ManagedFormResponse
|
|
261
267
|
> => {
|
|
262
|
-
|
|
268
|
+
authenticateProjectRequest(request, authRoutes, projectDomain);
|
|
263
269
|
|
|
270
|
+
let isManagedFormRequest = false;
|
|
264
271
|
try {
|
|
265
272
|
const url = new URL(request.url);
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
273
|
+
isManagedFormRequest =
|
|
274
|
+
url.searchParams.get(managedFormRequestParamName) === "1";
|
|
275
|
+
url.searchParams.delete(managedFormRequestParamName);
|
|
276
|
+
if (!isManagedFormRequest) {
|
|
277
|
+
url.host = getRequestHost(request);
|
|
278
|
+
}
|
|
279
|
+
const formData = isManagedFormRequest
|
|
280
|
+
? await readFormDataWithLimit(request)
|
|
281
|
+
: await request.formData();
|
|
269
282
|
|
|
270
283
|
const system = {
|
|
271
|
-
params: {},
|
|
272
|
-
|
|
284
|
+
params: getRemixParams(params ?? {}),
|
|
285
|
+
...getSystemSearch(url.searchParams),
|
|
273
286
|
origin: url.origin,
|
|
274
287
|
pathname: url.pathname,
|
|
275
288
|
};
|
|
276
289
|
|
|
290
|
+
const managedFormIds = formData.getAll(managedFormIdFieldName);
|
|
291
|
+
if (!isManagedFormRequest && managedFormIds.length > 0) {
|
|
292
|
+
throw new Error("Invalid Form submission");
|
|
293
|
+
}
|
|
294
|
+
if (isManagedFormRequest) {
|
|
295
|
+
if (managedFormIds.length !== 1 || formData.has(formIdFieldName)) {
|
|
296
|
+
throw new Error("Invalid Form submission");
|
|
297
|
+
}
|
|
298
|
+
const protectedFetch = createManagedFormResourceFetch({
|
|
299
|
+
request,
|
|
300
|
+
context,
|
|
301
|
+
projectDomain,
|
|
302
|
+
});
|
|
303
|
+
return await handleManagedFormSubmission({
|
|
304
|
+
request,
|
|
305
|
+
formData,
|
|
306
|
+
url,
|
|
307
|
+
system,
|
|
308
|
+
configuration: (formId) => getManagedFormSubmissions().get(formId),
|
|
309
|
+
getGraph: getManagedFormResourceGraph,
|
|
310
|
+
createEmailSender: (formData) =>
|
|
311
|
+
createManagedFormEmailSender({ context, formData, projectId }),
|
|
312
|
+
validateEmail: validateManagedFormEmail,
|
|
313
|
+
resourceFetch: protectedFetch,
|
|
314
|
+
validateDestination: protectedFetch.validateDestination,
|
|
315
|
+
trustedIp:
|
|
316
|
+
typeof context === "object" &&
|
|
317
|
+
context !== null &&
|
|
318
|
+
"cloudflare" in context
|
|
319
|
+
? request.headers.get("cf-connecting-ip") ?? undefined
|
|
320
|
+
: undefined,
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
|
|
277
324
|
const resourceName = formData.get(formIdFieldName);
|
|
278
325
|
const generatedResources = getResources({ system });
|
|
279
326
|
const actionResource =
|
|
@@ -307,7 +354,7 @@ export const action = async ({
|
|
|
307
354
|
formData.delete(formIdFieldName);
|
|
308
355
|
formData.delete(formBotFieldName);
|
|
309
356
|
|
|
310
|
-
let result: Awaited<ReturnType<typeof
|
|
357
|
+
let result: Awaited<ReturnType<typeof loadResourceWithEmail>>;
|
|
311
358
|
if (actionResource === undefined) {
|
|
312
359
|
if (contactEmail === undefined) {
|
|
313
360
|
throw new Error("Contact email not found");
|
|
@@ -321,14 +368,14 @@ export const action = async ({
|
|
|
321
368
|
if (resource === undefined) {
|
|
322
369
|
throw Error("Resource not found");
|
|
323
370
|
}
|
|
324
|
-
result = await
|
|
371
|
+
result = await loadResourceWithEmail(fetch, resource);
|
|
325
372
|
} else {
|
|
326
373
|
const actionFetch = await createGeneratedAssetResourceFetch({
|
|
327
374
|
request,
|
|
328
375
|
context,
|
|
329
376
|
fallback: customFetch,
|
|
330
377
|
});
|
|
331
|
-
const results = await
|
|
378
|
+
const results = await loadResourcesWithEmail(
|
|
332
379
|
actionFetch,
|
|
333
380
|
{
|
|
334
381
|
...generatedResources.data,
|
|
@@ -347,7 +394,7 @@ export const action = async ({
|
|
|
347
394
|
if (actionResult === undefined) {
|
|
348
395
|
throw Error("Resource not found");
|
|
349
396
|
}
|
|
350
|
-
result = actionResult as Awaited<ReturnType<typeof
|
|
397
|
+
result = actionResult as Awaited<ReturnType<typeof loadResourceWithEmail>>;
|
|
351
398
|
}
|
|
352
399
|
const { ok, statusText } = result;
|
|
353
400
|
if (ok) {
|
|
@@ -357,6 +404,11 @@ export const action = async ({
|
|
|
357
404
|
} catch (error) {
|
|
358
405
|
console.error(error);
|
|
359
406
|
|
|
407
|
+
if (isManagedFormRequest) {
|
|
408
|
+
return getManagedFormFailure(
|
|
409
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
410
|
+
);
|
|
411
|
+
}
|
|
360
412
|
return {
|
|
361
413
|
success: false,
|
|
362
414
|
errors: [error instanceof Error ? error.message : "Unknown error"],
|
|
@@ -1,30 +1,12 @@
|
|
|
1
1
|
import { type LoaderFunctionArgs, redirect } from "react-router";
|
|
2
|
-
import { isLocalResource, loadResources } from "@webstudio-is/sdk/runtime";
|
|
3
|
-
import {
|
|
2
|
+
import { isLocalResource, loadResources, getSystemSearch } from "@webstudio-is/sdk/runtime";
|
|
3
|
+
import { authenticateProjectRequest } from "@webstudio-is/wsauth";
|
|
4
4
|
import { projectDomain } from "__CLIENT__";
|
|
5
5
|
import { getPageMeta, getRemixParams, getResources } from "__SERVER__";
|
|
6
6
|
import { sitemap } from "__SITEMAP__";
|
|
7
7
|
import { authRoutes } from "__AUTH__";
|
|
8
8
|
import { createGeneratedAssetResourceFetch } from "__ASSET_QUERY_RUNTIME__";
|
|
9
9
|
|
|
10
|
-
const authenticateProductionRequest = (request: Request) => {
|
|
11
|
-
const host =
|
|
12
|
-
request.headers.get("x-forwarded-host") ||
|
|
13
|
-
request.headers.get("host") ||
|
|
14
|
-
"";
|
|
15
|
-
|
|
16
|
-
const requestHost = host.split(":")[0];
|
|
17
|
-
if (
|
|
18
|
-
projectDomain !== undefined &&
|
|
19
|
-
(requestHost === projectDomain ||
|
|
20
|
-
requestHost.startsWith(`${projectDomain}.`))
|
|
21
|
-
) {
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return authenticateRequest(request, authRoutes);
|
|
26
|
-
};
|
|
27
|
-
|
|
28
10
|
const customFetch: typeof fetch = (input, init) => {
|
|
29
11
|
if (typeof input !== "string") {
|
|
30
12
|
return fetch(input, init);
|
|
@@ -57,7 +39,11 @@ const customFetch: typeof fetch = (input, init) => {
|
|
|
57
39
|
};
|
|
58
40
|
|
|
59
41
|
export const loader = async (arg: LoaderFunctionArgs) => {
|
|
60
|
-
const authRoute =
|
|
42
|
+
const authRoute = authenticateProjectRequest(
|
|
43
|
+
arg.request,
|
|
44
|
+
authRoutes,
|
|
45
|
+
projectDomain
|
|
46
|
+
);
|
|
61
47
|
|
|
62
48
|
const url = new URL(arg.request.url);
|
|
63
49
|
const host =
|
|
@@ -71,7 +57,7 @@ export const loader = async (arg: LoaderFunctionArgs) => {
|
|
|
71
57
|
|
|
72
58
|
const system = {
|
|
73
59
|
params,
|
|
74
|
-
|
|
60
|
+
...getSystemSearch(url.searchParams),
|
|
75
61
|
origin: url.origin,
|
|
76
62
|
pathname: url.pathname,
|
|
77
63
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { renderToString } from "react-dom/server";
|
|
2
2
|
import { type LoaderFunctionArgs, redirect } from "react-router";
|
|
3
|
-
import { isLocalResource, loadResources } from "@webstudio-is/sdk/runtime";
|
|
4
|
-
import {
|
|
3
|
+
import { isLocalResource, loadResources, getSystemSearch } from "@webstudio-is/sdk/runtime";
|
|
4
|
+
import { authenticateProjectRequest } from "@webstudio-is/wsauth";
|
|
5
5
|
import {
|
|
6
6
|
ReactSdkContext,
|
|
7
7
|
xmlNodeTagSuffix,
|
|
@@ -13,24 +13,6 @@ import { sitemap } from "__SITEMAP__";
|
|
|
13
13
|
import { authRoutes } from "__AUTH__";
|
|
14
14
|
import { createGeneratedAssetResourceFetch } from "__ASSET_QUERY_RUNTIME__";
|
|
15
15
|
|
|
16
|
-
const authenticateProductionRequest = (request: Request) => {
|
|
17
|
-
const host =
|
|
18
|
-
request.headers.get("x-forwarded-host") ||
|
|
19
|
-
request.headers.get("host") ||
|
|
20
|
-
"";
|
|
21
|
-
|
|
22
|
-
const requestHost = host.split(":")[0];
|
|
23
|
-
if (
|
|
24
|
-
projectDomain !== undefined &&
|
|
25
|
-
(requestHost === projectDomain ||
|
|
26
|
-
requestHost.startsWith(`${projectDomain}.`))
|
|
27
|
-
) {
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return authenticateRequest(request, authRoutes);
|
|
32
|
-
};
|
|
33
|
-
|
|
34
16
|
const customFetch: typeof fetch = (input, init) => {
|
|
35
17
|
if (typeof input !== "string") {
|
|
36
18
|
return fetch(input, init);
|
|
@@ -65,7 +47,11 @@ const customFetch: typeof fetch = (input, init) => {
|
|
|
65
47
|
};
|
|
66
48
|
|
|
67
49
|
export const loader = async (arg: LoaderFunctionArgs) => {
|
|
68
|
-
const authRoute =
|
|
50
|
+
const authRoute = authenticateProjectRequest(
|
|
51
|
+
arg.request,
|
|
52
|
+
authRoutes,
|
|
53
|
+
projectDomain
|
|
54
|
+
);
|
|
69
55
|
|
|
70
56
|
const url = new URL(arg.request.url);
|
|
71
57
|
const host =
|
|
@@ -79,7 +65,7 @@ export const loader = async (arg: LoaderFunctionArgs) => {
|
|
|
79
65
|
|
|
80
66
|
const system = {
|
|
81
67
|
params,
|
|
82
|
-
|
|
68
|
+
...getSystemSearch(url.searchParams),
|
|
83
69
|
origin: url.origin,
|
|
84
70
|
pathname: url.pathname,
|
|
85
71
|
};
|
|
@@ -15,14 +15,14 @@
|
|
|
15
15
|
"@react-router/fs-routes": "^7.5.3",
|
|
16
16
|
"@react-router/node": "^7.5.3",
|
|
17
17
|
"@react-router/serve": "^7.5.3",
|
|
18
|
-
"@webstudio-is/image": "0.
|
|
19
|
-
"@webstudio-is/react-sdk": "0.
|
|
20
|
-
"@webstudio-is/sdk": "0.
|
|
21
|
-
"@webstudio-is/sdk-components-animation": "0.
|
|
22
|
-
"@webstudio-is/sdk-components-react-radix": "0.
|
|
23
|
-
"@webstudio-is/sdk-components-react-router": "0.
|
|
24
|
-
"@webstudio-is/sdk-components-react": "0.
|
|
25
|
-
"@webstudio-is/wsauth": "0.
|
|
18
|
+
"@webstudio-is/image": "0.306.0",
|
|
19
|
+
"@webstudio-is/react-sdk": "0.306.0",
|
|
20
|
+
"@webstudio-is/sdk": "0.306.0",
|
|
21
|
+
"@webstudio-is/sdk-components-animation": "0.306.0",
|
|
22
|
+
"@webstudio-is/sdk-components-react-radix": "0.306.0",
|
|
23
|
+
"@webstudio-is/sdk-components-react-router": "0.306.0",
|
|
24
|
+
"@webstudio-is/sdk-components-react": "0.306.0",
|
|
25
|
+
"@webstudio-is/wsauth": "0.306.0",
|
|
26
26
|
"isbot": "^5.1.25",
|
|
27
27
|
"react": "18.3.0-canary-14898b6a9-20240318",
|
|
28
28
|
"react-dom": "18.3.0-canary-14898b6a9-20240318",
|