webstudio 0.267.0 → 0.268.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 +436 -7
- package/package.json +14 -13
- package/templates/cloudflare/package.json +1 -0
- package/templates/defaults/app/root.tsx +9 -0
- package/templates/defaults/app/route-templates/html.tsx +32 -2
- package/templates/defaults/app/route-templates/text.tsx +107 -0
- package/templates/defaults/app/route-templates/xml.tsx +28 -2
- package/templates/defaults/package.json +8 -7
- package/templates/internal/package.json +2 -1
- package/templates/react-router/app/root.tsx +15 -1
- package/templates/react-router/app/route-templates/html.tsx +32 -2
- package/templates/react-router/app/route-templates/text.tsx +107 -0
- package/templates/react-router/app/route-templates/xml.tsx +28 -2
- package/templates/react-router/package.json +8 -7
- package/templates/react-router-cloudflare/package.json +1 -0
- package/templates/ssg/package.json +6 -6
package/lib/cli.js
CHANGED
|
@@ -374,7 +374,7 @@ const getApiCompatibilityPayload = (value) => {
|
|
|
374
374
|
return findPayload(value, /* @__PURE__ */ new WeakSet());
|
|
375
375
|
};
|
|
376
376
|
const name = "webstudio";
|
|
377
|
-
const version = "0.
|
|
377
|
+
const version = "0.268.0";
|
|
378
378
|
const description = "Webstudio CLI";
|
|
379
379
|
const author = "Webstudio <github@webstudio.is>";
|
|
380
380
|
const homepage = "https://webstudio.is";
|
|
@@ -386,7 +386,7 @@ const scripts = { "typecheck": "tsgo --noEmit", "build": "rm -rf lib && vite bui
|
|
|
386
386
|
const license = "AGPL-3.0-or-later";
|
|
387
387
|
const engines = { "node": ">=22" };
|
|
388
388
|
const dependencies = { "@clack/prompts": "^0.10.0", "@emotion/hash": "^0.9.2", "@trpc/client": "^10.45.2", "@webstudio-is/project-migrations": "workspace:*", "@webstudio-is/trpc-interface": "workspace:*", "acorn": "^8.14.1", "acorn-walk": "^8.3.4", "change-case": "^5.4.4", "deepmerge": "^4.3.1", "env-paths": "^3.0.0", "nanoid": "^5.1.5", "p-limit": "^6.2.0", "parse5": "7.3.0", "picocolors": "^1.1.1", "reserved-identifiers": "^1.0.0", "tinyexec": "^0.3.2", "warn-once": "^0.1.1", "yargs": "^17.7.2", "zod": "^3.24.2" };
|
|
389
|
-
const devDependencies = { "@cloudflare/vite-plugin": "^1.1.0", "@netlify/vite-plugin-react-router": "^1.0.1", "@react-router/dev": "^7.5.3", "@react-router/fs-routes": "^7.5.3", "@remix-run/cloudflare": "^2.16.5", "@remix-run/cloudflare-pages": "^2.16.5", "@remix-run/dev": "^2.16.5", "@remix-run/node": "^2.16.5", "@remix-run/react": "^2.16.5", "@remix-run/server-runtime": "^2.16.5", "@types/react": "^18.2.70", "@types/react-dom": "^18.2.25", "@types/yargs": "^17.0.33", "@vercel/react-router": "^1.1.0", "@vitejs/plugin-react": "^4.4.1", "@webstudio-is/css-engine": "workspace:*", "@webstudio-is/http-client": "workspace:*", "@webstudio-is/image": "workspace:*", "@webstudio-is/react-sdk": "workspace:*", "@webstudio-is/sdk": "workspace:*", "@webstudio-is/sdk-components-animation": "workspace:*", "@webstudio-is/sdk-components-react": "workspace:*", "@webstudio-is/sdk-components-react-radix": "workspace:*", "@webstudio-is/sdk-components-react-remix": "workspace:*", "@webstudio-is/sdk-components-react-router": "workspace:*", "@webstudio-is/tsconfig": "workspace:*", "h3": "^1.15.1", "ipx": "^3.0.3", "isbot": "^5.1.25", "prettier": "3.5.3", "react": "18.3.0-canary-14898b6a9-20240318", "react-dom": "18.3.0-canary-14898b6a9-20240318", "react-router": "^7.5.3", "ts-expect": "^1.3.0", "vike": "^0.4.229", "vite": "^6.3.4", "vitest": "^3.1.2", "wrangler": "^3.63.2" };
|
|
389
|
+
const devDependencies = { "@cloudflare/vite-plugin": "^1.1.0", "@netlify/vite-plugin-react-router": "^1.0.1", "@react-router/dev": "^7.5.3", "@react-router/fs-routes": "^7.5.3", "@remix-run/cloudflare": "^2.16.5", "@remix-run/cloudflare-pages": "^2.16.5", "@remix-run/dev": "^2.16.5", "@remix-run/node": "^2.16.5", "@remix-run/react": "^2.16.5", "@remix-run/server-runtime": "^2.16.5", "@types/react": "^18.2.70", "@types/react-dom": "^18.2.25", "@types/yargs": "^17.0.33", "@vercel/react-router": "^1.1.0", "@vitejs/plugin-react": "^4.4.1", "@webstudio-is/css-engine": "workspace:*", "@webstudio-is/http-client": "workspace:*", "@webstudio-is/image": "workspace:*", "@webstudio-is/react-sdk": "workspace:*", "@webstudio-is/sdk": "workspace:*", "@webstudio-is/sdk-components-animation": "workspace:*", "@webstudio-is/sdk-components-react": "workspace:*", "@webstudio-is/sdk-components-react-radix": "workspace:*", "@webstudio-is/sdk-components-react-remix": "workspace:*", "@webstudio-is/sdk-components-react-router": "workspace:*", "@webstudio-is/tsconfig": "workspace:*", "@webstudio-is/wsauth": "workspace:*", "h3": "^1.15.1", "ipx": "^3.0.3", "isbot": "^5.1.25", "prettier": "3.5.3", "react": "18.3.0-canary-14898b6a9-20240318", "react-dom": "18.3.0-canary-14898b6a9-20240318", "react-router": "^7.5.3", "ts-expect": "^1.3.0", "vike": "^0.4.229", "vite": "^6.3.4", "vitest": "^3.1.2", "wrangler": "^3.63.2" };
|
|
390
390
|
const packageJson = {
|
|
391
391
|
name,
|
|
392
392
|
version,
|
|
@@ -892,6 +892,293 @@ new Map(
|
|
|
892
892
|
return weightData.names.map((name2) => [name2, weight]);
|
|
893
893
|
}).flat()
|
|
894
894
|
);
|
|
895
|
+
var basicLoginErrors = (login) => {
|
|
896
|
+
const issues = [];
|
|
897
|
+
if (login.length === 0) {
|
|
898
|
+
issues.push({ path: ["login"], message: "Login is required" });
|
|
899
|
+
}
|
|
900
|
+
if (login.includes(":")) {
|
|
901
|
+
issues.push({ path: ["login"], message: "Login can't contain a colon" });
|
|
902
|
+
}
|
|
903
|
+
if (/\s/.test(login)) {
|
|
904
|
+
issues.push({
|
|
905
|
+
path: ["login"],
|
|
906
|
+
message: "Login can't contain whitespace"
|
|
907
|
+
});
|
|
908
|
+
}
|
|
909
|
+
return issues;
|
|
910
|
+
};
|
|
911
|
+
var basicPasswordErrors = (password) => {
|
|
912
|
+
const issues = [];
|
|
913
|
+
if (password.length === 0) {
|
|
914
|
+
issues.push({ path: ["password"], message: "Password is required" });
|
|
915
|
+
}
|
|
916
|
+
if (/\s/.test(password)) {
|
|
917
|
+
issues.push({
|
|
918
|
+
path: ["password"],
|
|
919
|
+
message: "Password can't contain whitespace"
|
|
920
|
+
});
|
|
921
|
+
}
|
|
922
|
+
return issues;
|
|
923
|
+
};
|
|
924
|
+
var validateBasicAuth = ({
|
|
925
|
+
login,
|
|
926
|
+
password
|
|
927
|
+
}) => {
|
|
928
|
+
const issues = [...basicLoginErrors(login), ...basicPasswordErrors(password)];
|
|
929
|
+
if (issues.length > 0) {
|
|
930
|
+
const loginErrors = issues.filter((issue) => issue.path[0] === "login").map((issue) => issue.message);
|
|
931
|
+
const passwordErrors = issues.filter((issue) => issue.path[0] === "password").map((issue) => issue.message);
|
|
932
|
+
return {
|
|
933
|
+
issues,
|
|
934
|
+
errors: {
|
|
935
|
+
login: loginErrors.length > 0 ? loginErrors : void 0,
|
|
936
|
+
password: passwordErrors.length > 0 ? passwordErrors : void 0
|
|
937
|
+
}
|
|
938
|
+
};
|
|
939
|
+
}
|
|
940
|
+
return {
|
|
941
|
+
auth: {
|
|
942
|
+
method: "basic",
|
|
943
|
+
login,
|
|
944
|
+
password,
|
|
945
|
+
credentials: `${login}:${password}`
|
|
946
|
+
}
|
|
947
|
+
};
|
|
948
|
+
};
|
|
949
|
+
var createBasicAuthRoute = ({
|
|
950
|
+
route,
|
|
951
|
+
login,
|
|
952
|
+
password
|
|
953
|
+
}) => {
|
|
954
|
+
const routeError = validateWsAuthRoute(route);
|
|
955
|
+
if (routeError) {
|
|
956
|
+
throw new Error(routeError);
|
|
957
|
+
}
|
|
958
|
+
const auth = validateBasicAuth({ login, password }).auth;
|
|
959
|
+
if (auth === void 0) {
|
|
960
|
+
throw new Error(
|
|
961
|
+
'Basic auth requires non-empty login and password; login cannot contain ":" and neither field can contain whitespace'
|
|
962
|
+
);
|
|
963
|
+
}
|
|
964
|
+
return { route, auth };
|
|
965
|
+
};
|
|
966
|
+
var createWsAuthRouteFromPage = ({
|
|
967
|
+
route,
|
|
968
|
+
auth
|
|
969
|
+
}) => {
|
|
970
|
+
if (auth === void 0) {
|
|
971
|
+
return;
|
|
972
|
+
}
|
|
973
|
+
if ("method" in auth && auth.method !== "basic" || "type" in auth && auth.type !== "basic") {
|
|
974
|
+
throw new Error(`Unsupported auth method for route "${route}"`);
|
|
975
|
+
}
|
|
976
|
+
return createBasicAuthRoute({
|
|
977
|
+
route,
|
|
978
|
+
login: auth.login,
|
|
979
|
+
password: auth.password
|
|
980
|
+
});
|
|
981
|
+
};
|
|
982
|
+
var isRecord = (value) => {
|
|
983
|
+
return typeof value === "object" && value !== null && Array.isArray(value) === false;
|
|
984
|
+
};
|
|
985
|
+
var parameterSegment = /^:\w+[?*]?$/;
|
|
986
|
+
var validateWsAuthRoute = (route) => {
|
|
987
|
+
if (route.startsWith("/") === false) {
|
|
988
|
+
return 'Route must start with "/"';
|
|
989
|
+
}
|
|
990
|
+
if (route === "/") {
|
|
991
|
+
return;
|
|
992
|
+
}
|
|
993
|
+
if (route !== "/" && route.endsWith("/")) {
|
|
994
|
+
return 'Route must not end with "/"';
|
|
995
|
+
}
|
|
996
|
+
if (route.includes("//")) {
|
|
997
|
+
return 'Route must not contain repeating "/"';
|
|
998
|
+
}
|
|
999
|
+
const segments = route.slice(1).split("/");
|
|
1000
|
+
for (let index = 0; index < segments.length; index += 1) {
|
|
1001
|
+
const segment = segments[index];
|
|
1002
|
+
if (segment === void 0 || segment === "") {
|
|
1003
|
+
return "Route contains an empty segment";
|
|
1004
|
+
}
|
|
1005
|
+
if (segment === "*" || /^:\w+\*$/.test(segment)) {
|
|
1006
|
+
if (index !== segments.length - 1) {
|
|
1007
|
+
return "Wildcard route segment must be the last segment";
|
|
1008
|
+
}
|
|
1009
|
+
continue;
|
|
1010
|
+
}
|
|
1011
|
+
if (segment.startsWith(":") && parameterSegment.test(segment) === false) {
|
|
1012
|
+
return `Invalid route parameter "${segment}"`;
|
|
1013
|
+
}
|
|
1014
|
+
if (segment.includes("*")) {
|
|
1015
|
+
return "Wildcard can only be used as * or :name*";
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
};
|
|
1019
|
+
var parseJson = (content, errors) => {
|
|
1020
|
+
if (content.trim() === "") {
|
|
1021
|
+
return { version: 1, routes: {} };
|
|
1022
|
+
}
|
|
1023
|
+
try {
|
|
1024
|
+
return JSON.parse(content);
|
|
1025
|
+
} catch (error) {
|
|
1026
|
+
errors.push({
|
|
1027
|
+
path: "$",
|
|
1028
|
+
message: error instanceof Error ? error.message : "Invalid JSON"
|
|
1029
|
+
});
|
|
1030
|
+
}
|
|
1031
|
+
};
|
|
1032
|
+
var parseWsAuth = (content) => {
|
|
1033
|
+
const routes = [];
|
|
1034
|
+
const errors = [];
|
|
1035
|
+
const json = parseJson(content, errors);
|
|
1036
|
+
if (json === void 0) {
|
|
1037
|
+
return { routes, errors };
|
|
1038
|
+
}
|
|
1039
|
+
if (isRecord(json) === false) {
|
|
1040
|
+
errors.push({ path: "$", message: "Auth config must be an object" });
|
|
1041
|
+
return { routes, errors };
|
|
1042
|
+
}
|
|
1043
|
+
if (json.version !== 1) {
|
|
1044
|
+
errors.push({ path: "version", message: "Version must be 1" });
|
|
1045
|
+
}
|
|
1046
|
+
if (isRecord(json.routes) === false) {
|
|
1047
|
+
errors.push({ path: "routes", message: "Routes must be an object" });
|
|
1048
|
+
return { routes, errors };
|
|
1049
|
+
}
|
|
1050
|
+
for (const [route, authInput] of Object.entries(json.routes)) {
|
|
1051
|
+
const routeError = validateWsAuthRoute(route);
|
|
1052
|
+
if (routeError) {
|
|
1053
|
+
errors.push({
|
|
1054
|
+
path: `routes.${JSON.stringify(route)}`,
|
|
1055
|
+
message: routeError
|
|
1056
|
+
});
|
|
1057
|
+
continue;
|
|
1058
|
+
}
|
|
1059
|
+
if (isRecord(authInput) === false) {
|
|
1060
|
+
errors.push({
|
|
1061
|
+
path: `routes.${JSON.stringify(route)}`,
|
|
1062
|
+
message: "Auth rule must be an object"
|
|
1063
|
+
});
|
|
1064
|
+
continue;
|
|
1065
|
+
}
|
|
1066
|
+
if (authInput.method !== "basic") {
|
|
1067
|
+
errors.push({
|
|
1068
|
+
path: `routes.${JSON.stringify(route)}.method`,
|
|
1069
|
+
message: 'Auth method must be "basic"'
|
|
1070
|
+
});
|
|
1071
|
+
continue;
|
|
1072
|
+
}
|
|
1073
|
+
const login = authInput.login;
|
|
1074
|
+
const password = authInput.password;
|
|
1075
|
+
if (typeof login !== "string") {
|
|
1076
|
+
errors.push({
|
|
1077
|
+
path: `routes.${JSON.stringify(route)}.login`,
|
|
1078
|
+
message: "Login must be a string"
|
|
1079
|
+
});
|
|
1080
|
+
continue;
|
|
1081
|
+
}
|
|
1082
|
+
if (typeof password !== "string") {
|
|
1083
|
+
errors.push({
|
|
1084
|
+
path: `routes.${JSON.stringify(route)}.password`,
|
|
1085
|
+
message: "Password must be a string"
|
|
1086
|
+
});
|
|
1087
|
+
continue;
|
|
1088
|
+
}
|
|
1089
|
+
const validation = validateBasicAuth({ login, password });
|
|
1090
|
+
if (validation.auth === void 0) {
|
|
1091
|
+
for (const issue of validation.issues ?? []) {
|
|
1092
|
+
errors.push({
|
|
1093
|
+
path: `routes.${JSON.stringify(route)}.${issue.path[0]}`,
|
|
1094
|
+
message: issue.message
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
1097
|
+
continue;
|
|
1098
|
+
}
|
|
1099
|
+
const auth = validation.auth;
|
|
1100
|
+
routes.push({ route, auth });
|
|
1101
|
+
}
|
|
1102
|
+
return { routes, errors };
|
|
1103
|
+
};
|
|
1104
|
+
var parseWsAuthOrThrow = (content, sourceName) => {
|
|
1105
|
+
const result = parseWsAuth(content);
|
|
1106
|
+
if (result.errors.length > 0) {
|
|
1107
|
+
const message = result.errors.map((error) => `${sourceName}:${error.path} ${error.message}`).join("\n");
|
|
1108
|
+
throw new Error(message);
|
|
1109
|
+
}
|
|
1110
|
+
return result.routes;
|
|
1111
|
+
};
|
|
1112
|
+
var serializeWsAuth = (routes) => {
|
|
1113
|
+
const config = { version: 1, routes: {} };
|
|
1114
|
+
for (const { route, auth } of routes) {
|
|
1115
|
+
switch (auth.method) {
|
|
1116
|
+
case "basic":
|
|
1117
|
+
config.routes[route] = {
|
|
1118
|
+
method: "basic",
|
|
1119
|
+
login: auth.login,
|
|
1120
|
+
password: auth.password
|
|
1121
|
+
};
|
|
1122
|
+
break;
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
return `${JSON.stringify(config, null, 2)}
|
|
1126
|
+
`;
|
|
1127
|
+
};
|
|
1128
|
+
var collectWsAuthRoutes = (sources) => {
|
|
1129
|
+
return sources.flatMap((source) => {
|
|
1130
|
+
if ("content" in source) {
|
|
1131
|
+
return parseWsAuthOrThrow(source.content, source.name);
|
|
1132
|
+
}
|
|
1133
|
+
return source.routes;
|
|
1134
|
+
});
|
|
1135
|
+
};
|
|
1136
|
+
var buildWsAuth = (sources) => {
|
|
1137
|
+
const content = serializeWsAuth(collectWsAuthRoutes(sources));
|
|
1138
|
+
const routes = parseWsAuthOrThrow(content, "Serialized auth config");
|
|
1139
|
+
return {
|
|
1140
|
+
routes,
|
|
1141
|
+
content
|
|
1142
|
+
};
|
|
1143
|
+
};
|
|
1144
|
+
var createWsAuthResources = ({
|
|
1145
|
+
projectContent = "",
|
|
1146
|
+
pages,
|
|
1147
|
+
projectSourceName = "Auth",
|
|
1148
|
+
generatedSourceName = "Generated page auth"
|
|
1149
|
+
}) => {
|
|
1150
|
+
const generatedRoutes = pages.flatMap((page) => {
|
|
1151
|
+
const route = createWsAuthRouteFromPage(page);
|
|
1152
|
+
return route === void 0 ? [] : [route];
|
|
1153
|
+
});
|
|
1154
|
+
const result = buildWsAuth([
|
|
1155
|
+
{ name: projectSourceName, content: projectContent },
|
|
1156
|
+
{ name: generatedSourceName, routes: generatedRoutes }
|
|
1157
|
+
]);
|
|
1158
|
+
console.info("[wsauth] create resources", {
|
|
1159
|
+
projectContentLength: projectContent.length,
|
|
1160
|
+
projectContent,
|
|
1161
|
+
pageCount: pages.length,
|
|
1162
|
+
pages,
|
|
1163
|
+
generatedRouteCount: generatedRoutes.length,
|
|
1164
|
+
generatedRoutes,
|
|
1165
|
+
routeCount: result.routes.length,
|
|
1166
|
+
routes: result.routes
|
|
1167
|
+
});
|
|
1168
|
+
return {
|
|
1169
|
+
...result,
|
|
1170
|
+
module: [
|
|
1171
|
+
`import type { WsAuthRoute } from "@webstudio-is/wsauth";`,
|
|
1172
|
+
"",
|
|
1173
|
+
`export const authRoutes: WsAuthRoute[] = ${JSON.stringify(
|
|
1174
|
+
result.routes,
|
|
1175
|
+
null,
|
|
1176
|
+
2
|
|
1177
|
+
)};`,
|
|
1178
|
+
""
|
|
1179
|
+
].join("\n")
|
|
1180
|
+
};
|
|
1181
|
+
};
|
|
895
1182
|
function dot3(a2, b2) {
|
|
896
1183
|
return a2[0] * b2[0] + a2[1] * b2[1] + a2[2] * b2[2];
|
|
897
1184
|
}
|
|
@@ -2687,8 +2974,19 @@ const oklch = new ColorSpace({
|
|
|
2687
2974
|
}
|
|
2688
2975
|
}
|
|
2689
2976
|
});
|
|
2977
|
+
var isKeyword = (value, keyword) => {
|
|
2978
|
+
if (value.type === "keyword") {
|
|
2979
|
+
return value.value === keyword;
|
|
2980
|
+
}
|
|
2981
|
+
if (value.type === "layers") {
|
|
2982
|
+
return value.value.some((layer) => isKeyword(layer, keyword));
|
|
2983
|
+
}
|
|
2984
|
+
return false;
|
|
2985
|
+
};
|
|
2690
2986
|
var prefixStyles = (styleMap) => {
|
|
2691
2987
|
const newStyleMap = /* @__PURE__ */ new Map();
|
|
2988
|
+
const backgroundClip = styleMap.get("background-clip");
|
|
2989
|
+
const hasTextBackgroundClip = backgroundClip !== void 0 && isKeyword(backgroundClip, "text");
|
|
2692
2990
|
for (const [property, value] of styleMap) {
|
|
2693
2991
|
if (property === "background-clip") {
|
|
2694
2992
|
newStyleMap.set("-webkit-background-clip", value);
|
|
@@ -2702,6 +3000,9 @@ var prefixStyles = (styleMap) => {
|
|
|
2702
3000
|
if (property === "backdrop-filter") {
|
|
2703
3001
|
newStyleMap.set("-webkit-backdrop-filter", value);
|
|
2704
3002
|
}
|
|
3003
|
+
if (property === "color" && hasTextBackgroundClip && isKeyword(value, "transparent")) {
|
|
3004
|
+
newStyleMap.set("-webkit-text-fill-color", value);
|
|
3005
|
+
}
|
|
2705
3006
|
if (property === "view-timeline-name" || property === "scroll-timeline-name" || property === "view-timeline-inset") {
|
|
2706
3007
|
newStyleMap.set(`--${property}`, value);
|
|
2707
3008
|
}
|
|
@@ -3807,7 +4108,36 @@ var PageTitle = z.string().refine(
|
|
|
3807
4108
|
(val) => val.length >= MIN_TITLE_LENGTH,
|
|
3808
4109
|
`Minimum ${MIN_TITLE_LENGTH} characters required`
|
|
3809
4110
|
);
|
|
3810
|
-
var documentTypes = ["html", "xml"];
|
|
4111
|
+
var documentTypes = ["html", "xml", "text"];
|
|
4112
|
+
var BasicAuthFields = {
|
|
4113
|
+
login: z.string(),
|
|
4114
|
+
password: z.string()
|
|
4115
|
+
};
|
|
4116
|
+
var validateBasicAuthFields = ({
|
|
4117
|
+
login,
|
|
4118
|
+
password
|
|
4119
|
+
}, context) => {
|
|
4120
|
+
for (const issue of validateBasicAuth({ login, password }).issues ?? []) {
|
|
4121
|
+
context.addIssue({
|
|
4122
|
+
code: z.ZodIssueCode.custom,
|
|
4123
|
+
path: issue.path,
|
|
4124
|
+
message: issue.message
|
|
4125
|
+
});
|
|
4126
|
+
}
|
|
4127
|
+
};
|
|
4128
|
+
var PageBasicAuth = z.object({
|
|
4129
|
+
method: z.literal("basic"),
|
|
4130
|
+
...BasicAuthFields
|
|
4131
|
+
}).superRefine(validateBasicAuthFields);
|
|
4132
|
+
var LegacyPageBasicAuth = z.object({
|
|
4133
|
+
type: z.literal("basic"),
|
|
4134
|
+
...BasicAuthFields
|
|
4135
|
+
}).superRefine(validateBasicAuthFields).transform(({ login, password }) => ({
|
|
4136
|
+
method: "basic",
|
|
4137
|
+
login,
|
|
4138
|
+
password
|
|
4139
|
+
}));
|
|
4140
|
+
var PageAuth = z.union([PageBasicAuth, LegacyPageBasicAuth]);
|
|
3811
4141
|
var commonPageFields = {
|
|
3812
4142
|
id: PageId,
|
|
3813
4143
|
name: PageName,
|
|
@@ -3825,6 +4155,8 @@ var commonPageFields = {
|
|
|
3825
4155
|
status: z.string().optional(),
|
|
3826
4156
|
redirect: z.string().optional(),
|
|
3827
4157
|
documentType: z.optional(z.enum(documentTypes)),
|
|
4158
|
+
content: z.string().optional(),
|
|
4159
|
+
auth: PageAuth.optional(),
|
|
3828
4160
|
custom: z.array(
|
|
3829
4161
|
z.object({
|
|
3830
4162
|
property: z.string(),
|
|
@@ -3880,7 +4212,8 @@ var ProjectMeta = z.object({
|
|
|
3880
4212
|
siteName: z.string().optional(),
|
|
3881
4213
|
contactEmail: z.string().optional(),
|
|
3882
4214
|
faviconAssetId: z.string().optional(),
|
|
3883
|
-
code: z.string().optional()
|
|
4215
|
+
code: z.string().optional(),
|
|
4216
|
+
auth: z.string().optional()
|
|
3884
4217
|
});
|
|
3885
4218
|
var ProjectNewRedirectPath = z.string().min(1, "Path is required").refine((data) => {
|
|
3886
4219
|
try {
|
|
@@ -4697,6 +5030,7 @@ var componentCategories = [
|
|
|
4697
5030
|
"localization",
|
|
4698
5031
|
"radix",
|
|
4699
5032
|
"xml",
|
|
5033
|
+
"text",
|
|
4700
5034
|
"other",
|
|
4701
5035
|
"hidden",
|
|
4702
5036
|
"internal"
|
|
@@ -5624,6 +5958,31 @@ var systemParameter = {
|
|
|
5624
5958
|
type: "parameter",
|
|
5625
5959
|
name: "system"
|
|
5626
5960
|
};
|
|
5961
|
+
var stringMethodReturnKindByName = /* @__PURE__ */ new Map([
|
|
5962
|
+
["toLowerCase", "string"],
|
|
5963
|
+
["replace", "string"],
|
|
5964
|
+
["split", "array"],
|
|
5965
|
+
["slice", "string"],
|
|
5966
|
+
["at", "unknown"],
|
|
5967
|
+
["endsWith", "boolean"],
|
|
5968
|
+
["includes", "boolean"],
|
|
5969
|
+
["startsWith", "boolean"],
|
|
5970
|
+
["toString", "string"],
|
|
5971
|
+
["toUpperCase", "string"],
|
|
5972
|
+
["toLocaleLowerCase", "string"],
|
|
5973
|
+
["toLocaleUpperCase", "string"]
|
|
5974
|
+
]);
|
|
5975
|
+
var arrayMethodReturnKindByName = /* @__PURE__ */ new Map([
|
|
5976
|
+
["at", "unknown"],
|
|
5977
|
+
["includes", "boolean"],
|
|
5978
|
+
["join", "string"],
|
|
5979
|
+
["slice", "array"],
|
|
5980
|
+
["toString", "string"]
|
|
5981
|
+
]);
|
|
5982
|
+
new Set(
|
|
5983
|
+
stringMethodReturnKindByName.keys()
|
|
5984
|
+
);
|
|
5985
|
+
new Set(arrayMethodReturnKindByName.keys());
|
|
5627
5986
|
var transpileExpression = ({
|
|
5628
5987
|
expression,
|
|
5629
5988
|
executable = false,
|
|
@@ -6063,6 +6422,12 @@ var generatePageMeta = ({
|
|
|
6063
6422
|
usedDataSources,
|
|
6064
6423
|
scope: localScope
|
|
6065
6424
|
});
|
|
6425
|
+
const contentExpression = generateExpression({
|
|
6426
|
+
expression: page.meta.content ?? "undefined",
|
|
6427
|
+
dataSources,
|
|
6428
|
+
usedDataSources,
|
|
6429
|
+
scope: localScope
|
|
6430
|
+
});
|
|
6066
6431
|
let customExpression = "";
|
|
6067
6432
|
customExpression += `[
|
|
6068
6433
|
`;
|
|
@@ -6071,7 +6436,7 @@ var generatePageMeta = ({
|
|
|
6071
6436
|
continue;
|
|
6072
6437
|
}
|
|
6073
6438
|
const propertyExpression = JSON.stringify(customMeta.property);
|
|
6074
|
-
const
|
|
6439
|
+
const contentExpression2 = generateExpression({
|
|
6075
6440
|
expression: customMeta.content,
|
|
6076
6441
|
dataSources,
|
|
6077
6442
|
usedDataSources,
|
|
@@ -6081,7 +6446,7 @@ var generatePageMeta = ({
|
|
|
6081
6446
|
`;
|
|
6082
6447
|
customExpression += ` property: ${propertyExpression},
|
|
6083
6448
|
`;
|
|
6084
|
-
customExpression += ` content: ${
|
|
6449
|
+
customExpression += ` content: ${contentExpression2},
|
|
6085
6450
|
`;
|
|
6086
6451
|
customExpression += ` },
|
|
6087
6452
|
`;
|
|
@@ -6146,6 +6511,8 @@ var generatePageMeta = ({
|
|
|
6146
6511
|
generated += ` status: ${statusExpression},
|
|
6147
6512
|
`;
|
|
6148
6513
|
generated += ` redirect: ${redirectExpression},
|
|
6514
|
+
`;
|
|
6515
|
+
generated += ` content: ${contentExpression},
|
|
6149
6516
|
`;
|
|
6150
6517
|
generated += ` custom: ${customExpression},
|
|
6151
6518
|
`;
|
|
@@ -10547,6 +10914,10 @@ const createFramework$2 = async () => {
|
|
|
10547
10914
|
join(routeTemplatesDir, "xml.tsx"),
|
|
10548
10915
|
"utf8"
|
|
10549
10916
|
);
|
|
10917
|
+
const textTemplate = await readFile(
|
|
10918
|
+
join(routeTemplatesDir, "text.tsx"),
|
|
10919
|
+
"utf8"
|
|
10920
|
+
);
|
|
10550
10921
|
const defaultSitemapTemplate = await readFile(
|
|
10551
10922
|
join(routeTemplatesDir, "default-sitemap.tsx"),
|
|
10552
10923
|
"utf8"
|
|
@@ -10600,6 +10971,12 @@ const createFramework$2 = async () => {
|
|
|
10600
10971
|
template: xmlTemplate
|
|
10601
10972
|
}
|
|
10602
10973
|
],
|
|
10974
|
+
text: ({ pagePath }) => [
|
|
10975
|
+
{
|
|
10976
|
+
file: join("app", "routes", `${generateRemixRoute(pagePath)}.tsx`),
|
|
10977
|
+
template: textTemplate
|
|
10978
|
+
}
|
|
10979
|
+
],
|
|
10603
10980
|
redirect: ({ pagePath }) => [
|
|
10604
10981
|
{
|
|
10605
10982
|
file: join("app", "routes", `${generateRemixRoute(pagePath)}.ts`),
|
|
@@ -10628,6 +11005,10 @@ const createFramework$1 = async () => {
|
|
|
10628
11005
|
join(routeTemplatesDir, "xml.tsx"),
|
|
10629
11006
|
"utf8"
|
|
10630
11007
|
);
|
|
11008
|
+
const textTemplate = await readFile(
|
|
11009
|
+
join(routeTemplatesDir, "text.tsx"),
|
|
11010
|
+
"utf8"
|
|
11011
|
+
);
|
|
10631
11012
|
const defaultSitemapTemplate = await readFile(
|
|
10632
11013
|
join(routeTemplatesDir, "default-sitemap.tsx"),
|
|
10633
11014
|
"utf8"
|
|
@@ -10681,6 +11062,12 @@ const createFramework$1 = async () => {
|
|
|
10681
11062
|
template: xmlTemplate
|
|
10682
11063
|
}
|
|
10683
11064
|
],
|
|
11065
|
+
text: ({ pagePath }) => [
|
|
11066
|
+
{
|
|
11067
|
+
file: join("app", "routes", `${generateRemixRoute(pagePath)}.tsx`),
|
|
11068
|
+
template: textTemplate
|
|
11069
|
+
}
|
|
11070
|
+
],
|
|
10684
11071
|
redirect: ({ pagePath }) => [
|
|
10685
11072
|
{
|
|
10686
11073
|
file: join("app", "routes", `${generateRemixRoute(pagePath)}.ts`),
|
|
@@ -10765,11 +11152,13 @@ const createFramework = async () => {
|
|
|
10765
11152
|
];
|
|
10766
11153
|
},
|
|
10767
11154
|
xml: () => [],
|
|
11155
|
+
text: () => [],
|
|
10768
11156
|
redirect: () => [],
|
|
10769
11157
|
defaultSitemap: () => []
|
|
10770
11158
|
};
|
|
10771
11159
|
};
|
|
10772
11160
|
const limit = pLimit(10);
|
|
11161
|
+
const wsAuthFile = ".webstudio/auth.json";
|
|
10773
11162
|
const downloadAsset = async (url, name2, assetBaseUrl) => {
|
|
10774
11163
|
const assetPath = join("public", assetBaseUrl, name2);
|
|
10775
11164
|
const tempAssetPath = `${assetPath}.tmp`;
|
|
@@ -10813,6 +11202,40 @@ const mergeJsonInto = async (sourcePath, destinationPath) => {
|
|
|
10813
11202
|
);
|
|
10814
11203
|
await writeFile(destinationPath, content, "utf8");
|
|
10815
11204
|
};
|
|
11205
|
+
const writeWsAuthResources = async (generatedDir, pages) => {
|
|
11206
|
+
var _a2, _b2, _c2, _d2;
|
|
11207
|
+
console.info("[wsauth] prebuild create auth config", {
|
|
11208
|
+
file: wsAuthFile,
|
|
11209
|
+
projectAuthContentLength: ((_b2 = (_a2 = pages.meta) == null ? void 0 : _a2.auth) == null ? void 0 : _b2.length) ?? 0,
|
|
11210
|
+
projectAuthContent: (_c2 = pages.meta) == null ? void 0 : _c2.auth,
|
|
11211
|
+
pages: getAllPages(pages).map((page) => ({
|
|
11212
|
+
id: page.id,
|
|
11213
|
+
name: page.name,
|
|
11214
|
+
route: getPagePath(page.id, pages),
|
|
11215
|
+
auth: page.meta.auth
|
|
11216
|
+
}))
|
|
11217
|
+
});
|
|
11218
|
+
const { content, module } = createWsAuthResources({
|
|
11219
|
+
projectContent: (_d2 = pages.meta) == null ? void 0 : _d2.auth,
|
|
11220
|
+
pages: getAllPages(pages).map((page) => ({
|
|
11221
|
+
route: getPagePath(page.id, pages),
|
|
11222
|
+
auth: page.meta.auth
|
|
11223
|
+
}))
|
|
11224
|
+
});
|
|
11225
|
+
console.info("[wsauth] prebuild write auth config", {
|
|
11226
|
+
file: wsAuthFile,
|
|
11227
|
+
contentLength: content.length,
|
|
11228
|
+
content,
|
|
11229
|
+
generatedModulePath: join(generatedDir, "$resources.wsauth.server.ts"),
|
|
11230
|
+
generatedModule: module
|
|
11231
|
+
});
|
|
11232
|
+
await createFolderIfNotExists(dirname(wsAuthFile));
|
|
11233
|
+
await writeFile(wsAuthFile, content);
|
|
11234
|
+
await createFileIfNotExists(
|
|
11235
|
+
join(generatedDir, "$resources.wsauth.server.ts"),
|
|
11236
|
+
module
|
|
11237
|
+
);
|
|
11238
|
+
};
|
|
10816
11239
|
const isCliTemplate = async (template) => {
|
|
10817
11240
|
const currentPath = fileURLToPath(new URL(import.meta.url));
|
|
10818
11241
|
const templatesPath = normalize(
|
|
@@ -10913,6 +11336,7 @@ Please check webstudio --help for more details`
|
|
|
10913
11336
|
);
|
|
10914
11337
|
const pages = migratePages(siteData.build.pages);
|
|
10915
11338
|
const allPages = getAllPages(pages);
|
|
11339
|
+
await writeWsAuthResources(generatedDir, pages);
|
|
10916
11340
|
const siteDataByPage = {};
|
|
10917
11341
|
const fontAssetsByPage = {};
|
|
10918
11342
|
const backgroundImageAssetsByPage = {};
|
|
@@ -11149,6 +11573,8 @@ Please check webstudio --help for more details`
|
|
|
11149
11573
|
|
|
11150
11574
|
export const projectId = "${siteData.build.projectId}";
|
|
11151
11575
|
|
|
11576
|
+
export const projectDomain = ${JSON.stringify(siteData.projectDomain)};
|
|
11577
|
+
|
|
11152
11578
|
export const lastPublished = "${new Date(siteData.build.createdAt).toISOString()}";
|
|
11153
11579
|
|
|
11154
11580
|
export const siteName = ${JSON.stringify(projectMeta == null ? void 0 : projectMeta.siteName)};
|
|
@@ -11221,7 +11647,7 @@ Please check webstudio --help for more details`
|
|
|
11221
11647
|
await createFileIfNotExists(clientFile, pageExports);
|
|
11222
11648
|
const serverFile = join(generatedDir, `${generatedBasename}.server.tsx`);
|
|
11223
11649
|
await createFileIfNotExists(serverFile, serverExports);
|
|
11224
|
-
const getTemplates = documentType
|
|
11650
|
+
const getTemplates = framework[documentType];
|
|
11225
11651
|
for (const { file, template } of getTemplates({ pagePath })) {
|
|
11226
11652
|
const content = template.replaceAll("__CONSTANTS__", importFrom("./app/constants.mjs", file)).replaceAll(
|
|
11227
11653
|
"__SITEMAP__",
|
|
@@ -11229,6 +11655,9 @@ Please check webstudio --help for more details`
|
|
|
11229
11655
|
).replaceAll(
|
|
11230
11656
|
"__ASSETS__",
|
|
11231
11657
|
importFrom(`./app/__generated__/$resources.assets`, file)
|
|
11658
|
+
).replaceAll(
|
|
11659
|
+
"__AUTH__",
|
|
11660
|
+
importFrom(`./app/__generated__/$resources.wsauth.server`, file)
|
|
11232
11661
|
).replaceAll(
|
|
11233
11662
|
"__CLIENT__",
|
|
11234
11663
|
importFrom(`./app/__generated__/${generatedBasename}`, file)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webstudio",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.268.0",
|
|
4
4
|
"description": "Webstudio CLI",
|
|
5
5
|
"author": "Webstudio <github@webstudio.is>",
|
|
6
6
|
"homepage": "https://webstudio.is",
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
"warn-once": "^0.1.1",
|
|
44
44
|
"yargs": "^17.7.2",
|
|
45
45
|
"zod": "^3.24.2",
|
|
46
|
-
"@webstudio-is/
|
|
47
|
-
"@webstudio-is/
|
|
46
|
+
"@webstudio-is/trpc-interface": "0.268.0",
|
|
47
|
+
"@webstudio-is/project-migrations": "0.268.0"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@cloudflare/vite-plugin": "^1.1.0",
|
|
@@ -74,16 +74,17 @@
|
|
|
74
74
|
"vite": "^6.3.4",
|
|
75
75
|
"vitest": "^3.1.2",
|
|
76
76
|
"wrangler": "^3.63.2",
|
|
77
|
-
"@webstudio-is/css-engine": "0.
|
|
78
|
-
"@webstudio-is/http-client": "0.
|
|
79
|
-
"@webstudio-is/
|
|
80
|
-
"@webstudio-is/
|
|
81
|
-
"@webstudio-is/sdk": "0.
|
|
82
|
-
"@webstudio-is/sdk-components-animation": "0.
|
|
83
|
-
"@webstudio-is/sdk-components-react": "0.
|
|
84
|
-
"@webstudio-is/sdk-components-react-
|
|
85
|
-
"@webstudio-is/sdk-components-react-router": "0.
|
|
86
|
-
"@webstudio-is/sdk-components-react
|
|
77
|
+
"@webstudio-is/css-engine": "0.268.0",
|
|
78
|
+
"@webstudio-is/http-client": "0.268.0",
|
|
79
|
+
"@webstudio-is/image": "0.268.0",
|
|
80
|
+
"@webstudio-is/react-sdk": "0.268.0",
|
|
81
|
+
"@webstudio-is/sdk": "0.268.0",
|
|
82
|
+
"@webstudio-is/sdk-components-animation": "0.268.0",
|
|
83
|
+
"@webstudio-is/sdk-components-react-radix": "0.268.0",
|
|
84
|
+
"@webstudio-is/sdk-components-react-remix": "0.268.0",
|
|
85
|
+
"@webstudio-is/sdk-components-react-router": "0.268.0",
|
|
86
|
+
"@webstudio-is/sdk-components-react": "0.268.0",
|
|
87
|
+
"@webstudio-is/wsauth": "0.268.0",
|
|
87
88
|
"@webstudio-is/tsconfig": "1.0.7"
|
|
88
89
|
},
|
|
89
90
|
"scripts": {
|
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
2
2
|
|
|
3
3
|
import { Links, Meta, Outlet, useMatches } from "@remix-run/react";
|
|
4
|
+
import type { HeadersFunction } from "@remix-run/server-runtime";
|
|
4
5
|
// @todo think about how to make __generated__ typeable
|
|
5
6
|
// @ts-ignore
|
|
6
7
|
import { CustomCode, projectId, lastPublished } from "./__generated__/_index";
|
|
7
8
|
|
|
9
|
+
export const headers: HeadersFunction = ({ errorHeaders }) => {
|
|
10
|
+
if (errorHeaders) {
|
|
11
|
+
return errorHeaders;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return {};
|
|
15
|
+
};
|
|
16
|
+
|
|
8
17
|
const Root = () => {
|
|
9
18
|
// Get language from matches
|
|
10
19
|
const matches = useMatches();
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
formIdFieldName,
|
|
18
18
|
formBotFieldName,
|
|
19
19
|
} from "@webstudio-is/sdk/runtime";
|
|
20
|
+
import { authenticateRequest } from "@webstudio-is/wsauth";
|
|
20
21
|
import {
|
|
21
22
|
ReactSdkContext,
|
|
22
23
|
PageSettingsMeta,
|
|
@@ -25,6 +26,7 @@ import {
|
|
|
25
26
|
} from "@webstudio-is/react-sdk/runtime";
|
|
26
27
|
import {
|
|
27
28
|
projectId,
|
|
29
|
+
projectDomain,
|
|
28
30
|
Page,
|
|
29
31
|
siteName,
|
|
30
32
|
favIconAsset,
|
|
@@ -42,6 +44,25 @@ import * as constants from "__CONSTANTS__";
|
|
|
42
44
|
import css from "__CSS__?url";
|
|
43
45
|
import { sitemap } from "__SITEMAP__";
|
|
44
46
|
import { assets } from "__ASSETS__";
|
|
47
|
+
import { authRoutes } from "__AUTH__";
|
|
48
|
+
|
|
49
|
+
const authenticateProductionRequest = (request: Request) => {
|
|
50
|
+
const host =
|
|
51
|
+
request.headers.get("x-forwarded-host") ||
|
|
52
|
+
request.headers.get("host") ||
|
|
53
|
+
"";
|
|
54
|
+
|
|
55
|
+
const requestHost = host.split(":")[0];
|
|
56
|
+
if (
|
|
57
|
+
projectDomain !== undefined &&
|
|
58
|
+
(requestHost === projectDomain ||
|
|
59
|
+
requestHost.startsWith(`${projectDomain}.`))
|
|
60
|
+
) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return authenticateRequest(request, authRoutes);
|
|
65
|
+
};
|
|
45
66
|
|
|
46
67
|
const customFetch: typeof fetch = (input, init) => {
|
|
47
68
|
if (typeof input !== "string") {
|
|
@@ -83,6 +104,8 @@ const customFetch: typeof fetch = (input, init) => {
|
|
|
83
104
|
};
|
|
84
105
|
|
|
85
106
|
export const loader = async (arg: LoaderFunctionArgs) => {
|
|
107
|
+
const authRoute = authenticateProductionRequest(arg.request);
|
|
108
|
+
|
|
86
109
|
const url = new URL(arg.request.url);
|
|
87
110
|
const host =
|
|
88
111
|
arg.request.headers.get("x-forwarded-host") ||
|
|
@@ -133,13 +156,18 @@ export const loader = async (arg: LoaderFunctionArgs) => {
|
|
|
133
156
|
{
|
|
134
157
|
status: pageMeta.status,
|
|
135
158
|
headers: {
|
|
136
|
-
"Cache-Control":
|
|
159
|
+
"Cache-Control":
|
|
160
|
+
authRoute === undefined ? "public, max-age=600" : "private, no-store",
|
|
137
161
|
},
|
|
138
162
|
}
|
|
139
163
|
);
|
|
140
164
|
};
|
|
141
165
|
|
|
142
|
-
export const headers: HeadersFunction = () => {
|
|
166
|
+
export const headers: HeadersFunction = ({ errorHeaders }) => {
|
|
167
|
+
if (errorHeaders) {
|
|
168
|
+
return errorHeaders;
|
|
169
|
+
}
|
|
170
|
+
|
|
143
171
|
return {
|
|
144
172
|
"Cache-Control": "public, max-age=0, must-revalidate",
|
|
145
173
|
};
|
|
@@ -220,6 +248,8 @@ export const action = async ({
|
|
|
220
248
|
}: ActionFunctionArgs): Promise<
|
|
221
249
|
{ success: true } | { success: false; errors: string[] }
|
|
222
250
|
> => {
|
|
251
|
+
authenticateProductionRequest(request);
|
|
252
|
+
|
|
223
253
|
try {
|
|
224
254
|
const url = new URL(request.url);
|
|
225
255
|
url.host = getRequestHost(request);
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { type LoaderFunctionArgs, redirect } from "@remix-run/server-runtime";
|
|
2
|
+
import { isLocalResource, loadResources } from "@webstudio-is/sdk/runtime";
|
|
3
|
+
import { authenticateRequest } from "@webstudio-is/wsauth";
|
|
4
|
+
import { projectDomain } from "__CLIENT__";
|
|
5
|
+
import { getPageMeta, getRemixParams, getResources } from "__SERVER__";
|
|
6
|
+
import { sitemap } from "__SITEMAP__";
|
|
7
|
+
import { assets } from "__ASSETS__";
|
|
8
|
+
import { authRoutes } from "__AUTH__";
|
|
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
|
+
const customFetch: typeof fetch = (input, init) => {
|
|
29
|
+
if (typeof input !== "string") {
|
|
30
|
+
return fetch(input, init);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (isLocalResource(input, "sitemap.xml")) {
|
|
34
|
+
const response = new Response(JSON.stringify(sitemap));
|
|
35
|
+
response.headers.set("content-type", "application/json; charset=utf-8");
|
|
36
|
+
return Promise.resolve(response);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (isLocalResource(input, "current-date")) {
|
|
40
|
+
const now = new Date();
|
|
41
|
+
const startOfDay = new Date(
|
|
42
|
+
Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())
|
|
43
|
+
);
|
|
44
|
+
const data = {
|
|
45
|
+
iso: startOfDay.toISOString(),
|
|
46
|
+
year: startOfDay.getUTCFullYear(),
|
|
47
|
+
month: startOfDay.getUTCMonth() + 1,
|
|
48
|
+
day: startOfDay.getUTCDate(),
|
|
49
|
+
timestamp: startOfDay.getTime(),
|
|
50
|
+
};
|
|
51
|
+
const response = new Response(JSON.stringify(data));
|
|
52
|
+
response.headers.set("content-type", "application/json; charset=utf-8");
|
|
53
|
+
return Promise.resolve(response);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (isLocalResource(input, "assets")) {
|
|
57
|
+
const response = new Response(JSON.stringify(assets));
|
|
58
|
+
response.headers.set("content-type", "application/json; charset=utf-8");
|
|
59
|
+
return Promise.resolve(response);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return fetch(input, init);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const loader = async (arg: LoaderFunctionArgs) => {
|
|
66
|
+
const authRoute = authenticateProductionRequest(arg.request);
|
|
67
|
+
|
|
68
|
+
const url = new URL(arg.request.url);
|
|
69
|
+
const host =
|
|
70
|
+
arg.request.headers.get("x-forwarded-host") ||
|
|
71
|
+
arg.request.headers.get("host") ||
|
|
72
|
+
"";
|
|
73
|
+
url.host = host;
|
|
74
|
+
url.protocol = "https";
|
|
75
|
+
|
|
76
|
+
const params = getRemixParams(arg.params);
|
|
77
|
+
|
|
78
|
+
const system = {
|
|
79
|
+
params,
|
|
80
|
+
search: Object.fromEntries(url.searchParams),
|
|
81
|
+
origin: url.origin,
|
|
82
|
+
pathname: url.pathname,
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const resources = await loadResources(
|
|
86
|
+
customFetch,
|
|
87
|
+
getResources({ system }).data
|
|
88
|
+
);
|
|
89
|
+
const pageMeta = getPageMeta({ system, resources });
|
|
90
|
+
|
|
91
|
+
if (pageMeta.redirect) {
|
|
92
|
+
const status =
|
|
93
|
+
pageMeta.status === 301 || pageMeta.status === 302
|
|
94
|
+
? pageMeta.status
|
|
95
|
+
: 302;
|
|
96
|
+
return redirect(pageMeta.redirect, status);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return new Response(pageMeta.content ?? "", {
|
|
100
|
+
status: pageMeta.status,
|
|
101
|
+
headers: {
|
|
102
|
+
"Content-Type": "text/plain; charset=utf-8",
|
|
103
|
+
"Cache-Control":
|
|
104
|
+
authRoute === undefined ? "public, max-age=600" : "private, no-store",
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
};
|
|
@@ -1,15 +1,35 @@
|
|
|
1
1
|
import { renderToString } from "react-dom/server";
|
|
2
2
|
import { type LoaderFunctionArgs, redirect } from "@remix-run/server-runtime";
|
|
3
3
|
import { isLocalResource, loadResources } from "@webstudio-is/sdk/runtime";
|
|
4
|
+
import { authenticateRequest } from "@webstudio-is/wsauth";
|
|
4
5
|
import {
|
|
5
6
|
ReactSdkContext,
|
|
6
7
|
xmlNodeTagSuffix,
|
|
7
8
|
} from "@webstudio-is/react-sdk/runtime";
|
|
8
|
-
import { Page, breakpoints } from "__CLIENT__";
|
|
9
|
+
import { Page, breakpoints, projectDomain } from "__CLIENT__";
|
|
9
10
|
import { getPageMeta, getRemixParams, getResources } from "__SERVER__";
|
|
10
11
|
import { assetBaseUrl, imageLoader } from "__CONSTANTS__";
|
|
11
12
|
import { sitemap } from "__SITEMAP__";
|
|
12
13
|
import { assets } from "__ASSETS__";
|
|
14
|
+
import { authRoutes } from "__AUTH__";
|
|
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
|
+
};
|
|
13
33
|
|
|
14
34
|
const customFetch: typeof fetch = (input, init) => {
|
|
15
35
|
if (typeof input !== "string") {
|
|
@@ -51,6 +71,8 @@ const customFetch: typeof fetch = (input, init) => {
|
|
|
51
71
|
};
|
|
52
72
|
|
|
53
73
|
export const loader = async (arg: LoaderFunctionArgs) => {
|
|
74
|
+
const authRoute = authenticateProductionRequest(arg.request);
|
|
75
|
+
|
|
54
76
|
const url = new URL(arg.request.url);
|
|
55
77
|
const host =
|
|
56
78
|
arg.request.headers.get("x-forwarded-host") ||
|
|
@@ -104,6 +126,10 @@ export const loader = async (arg: LoaderFunctionArgs) => {
|
|
|
104
126
|
text = text.replaceAll(xmlNodeTagSuffix, "");
|
|
105
127
|
|
|
106
128
|
return new Response(`<?xml version="1.0" encoding="UTF-8"?>\n${text}`, {
|
|
107
|
-
headers: {
|
|
129
|
+
headers: {
|
|
130
|
+
"Content-Type": "application/xml",
|
|
131
|
+
"Cache-Control":
|
|
132
|
+
authRoute === undefined ? "public, max-age=600" : "private, no-store",
|
|
133
|
+
},
|
|
108
134
|
});
|
|
109
135
|
};
|
|
@@ -11,13 +11,14 @@
|
|
|
11
11
|
"@remix-run/node": "2.16.5",
|
|
12
12
|
"@remix-run/react": "2.16.5",
|
|
13
13
|
"@remix-run/server-runtime": "2.16.5",
|
|
14
|
-
"@webstudio-is/image": "0.
|
|
15
|
-
"@webstudio-is/react-sdk": "0.
|
|
16
|
-
"@webstudio-is/sdk": "0.
|
|
17
|
-
"@webstudio-is/sdk-components-react": "0.
|
|
18
|
-
"@webstudio-is/sdk-components-animation": "0.
|
|
19
|
-
"@webstudio-is/sdk-components-react-radix": "0.
|
|
20
|
-
"@webstudio-is/sdk-components-react-remix": "0.
|
|
14
|
+
"@webstudio-is/image": "0.268.0",
|
|
15
|
+
"@webstudio-is/react-sdk": "0.268.0",
|
|
16
|
+
"@webstudio-is/sdk": "0.268.0",
|
|
17
|
+
"@webstudio-is/sdk-components-react": "0.268.0",
|
|
18
|
+
"@webstudio-is/sdk-components-animation": "0.268.0",
|
|
19
|
+
"@webstudio-is/sdk-components-react-radix": "0.268.0",
|
|
20
|
+
"@webstudio-is/sdk-components-react-remix": "0.268.0",
|
|
21
|
+
"@webstudio-is/wsauth": "0.268.0",
|
|
21
22
|
"isbot": "^5.1.25",
|
|
22
23
|
"react": "18.3.0-canary-14898b6a9-20240318",
|
|
23
24
|
"react-dom": "18.3.0-canary-14898b6a9-20240318"
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"@webstudio-is/sdk-components-animation": "workspace:*",
|
|
7
7
|
"@webstudio-is/sdk-components-react": "workspace:*",
|
|
8
8
|
"@webstudio-is/sdk-components-react-radix": "workspace:*",
|
|
9
|
-
"@webstudio-is/sdk-components-react-remix": "workspace:*"
|
|
9
|
+
"@webstudio-is/sdk-components-react-remix": "workspace:*",
|
|
10
|
+
"@webstudio-is/wsauth": "workspace:*"
|
|
10
11
|
}
|
|
11
12
|
}
|
|
@@ -1,10 +1,24 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
type HeadersFunction,
|
|
5
|
+
Links,
|
|
6
|
+
Meta,
|
|
7
|
+
Outlet,
|
|
8
|
+
useMatches,
|
|
9
|
+
} from "react-router";
|
|
4
10
|
// @todo think about how to make __generated__ typeable
|
|
5
11
|
// @ts-ignore
|
|
6
12
|
import { CustomCode, projectId, lastPublished } from "./__generated__/_index";
|
|
7
13
|
|
|
14
|
+
export const headers: HeadersFunction = ({ errorHeaders }) => {
|
|
15
|
+
if (errorHeaders) {
|
|
16
|
+
return errorHeaders;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return {};
|
|
20
|
+
};
|
|
21
|
+
|
|
8
22
|
const Root = () => {
|
|
9
23
|
// Get language from matches
|
|
10
24
|
const matches = useMatches();
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
formBotFieldName,
|
|
18
18
|
cachedFetch,
|
|
19
19
|
} from "@webstudio-is/sdk/runtime";
|
|
20
|
+
import { authenticateRequest } from "@webstudio-is/wsauth";
|
|
20
21
|
import {
|
|
21
22
|
ReactSdkContext,
|
|
22
23
|
PageSettingsMeta,
|
|
@@ -24,6 +25,7 @@ import {
|
|
|
24
25
|
} from "@webstudio-is/react-sdk/runtime";
|
|
25
26
|
import {
|
|
26
27
|
projectId,
|
|
28
|
+
projectDomain,
|
|
27
29
|
Page,
|
|
28
30
|
siteName,
|
|
29
31
|
favIconAsset,
|
|
@@ -41,6 +43,25 @@ import * as constants from "__CONSTANTS__";
|
|
|
41
43
|
import css from "__CSS__?url";
|
|
42
44
|
import { sitemap } from "__SITEMAP__";
|
|
43
45
|
import { assets } from "__ASSETS__";
|
|
46
|
+
import { authRoutes } from "__AUTH__";
|
|
47
|
+
|
|
48
|
+
const authenticateProductionRequest = (request: Request) => {
|
|
49
|
+
const host =
|
|
50
|
+
request.headers.get("x-forwarded-host") ||
|
|
51
|
+
request.headers.get("host") ||
|
|
52
|
+
"";
|
|
53
|
+
|
|
54
|
+
const requestHost = host.split(":")[0];
|
|
55
|
+
if (
|
|
56
|
+
projectDomain !== undefined &&
|
|
57
|
+
(requestHost === projectDomain ||
|
|
58
|
+
requestHost.startsWith(`${projectDomain}.`))
|
|
59
|
+
) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return authenticateRequest(request, authRoutes);
|
|
64
|
+
};
|
|
44
65
|
|
|
45
66
|
const customFetch: typeof fetch = (input, init) => {
|
|
46
67
|
if (typeof input !== "string") {
|
|
@@ -82,6 +103,8 @@ const customFetch: typeof fetch = (input, init) => {
|
|
|
82
103
|
};
|
|
83
104
|
|
|
84
105
|
export const loader = async (arg: LoaderFunctionArgs) => {
|
|
106
|
+
const authRoute = authenticateProductionRequest(arg.request);
|
|
107
|
+
|
|
85
108
|
const url = new URL(arg.request.url);
|
|
86
109
|
const host =
|
|
87
110
|
arg.request.headers.get("x-forwarded-host") ||
|
|
@@ -132,13 +155,18 @@ export const loader = async (arg: LoaderFunctionArgs) => {
|
|
|
132
155
|
{
|
|
133
156
|
status: pageMeta.status,
|
|
134
157
|
headers: {
|
|
135
|
-
"Cache-Control":
|
|
158
|
+
"Cache-Control":
|
|
159
|
+
authRoute === undefined ? "public, max-age=600" : "private, no-store",
|
|
136
160
|
},
|
|
137
161
|
}
|
|
138
162
|
);
|
|
139
163
|
};
|
|
140
164
|
|
|
141
|
-
export const headers: HeadersFunction = () => {
|
|
165
|
+
export const headers: HeadersFunction = ({ errorHeaders }) => {
|
|
166
|
+
if (errorHeaders) {
|
|
167
|
+
return errorHeaders;
|
|
168
|
+
}
|
|
169
|
+
|
|
142
170
|
return {
|
|
143
171
|
"Cache-Control": "public, max-age=0, must-revalidate",
|
|
144
172
|
};
|
|
@@ -219,6 +247,8 @@ export const action = async ({
|
|
|
219
247
|
}: ActionFunctionArgs): Promise<
|
|
220
248
|
{ success: true } | { success: false; errors: string[] }
|
|
221
249
|
> => {
|
|
250
|
+
authenticateProductionRequest(request);
|
|
251
|
+
|
|
222
252
|
try {
|
|
223
253
|
const url = new URL(request.url);
|
|
224
254
|
url.host = getRequestHost(request);
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { type LoaderFunctionArgs, redirect } from "react-router";
|
|
2
|
+
import { isLocalResource, loadResources } from "@webstudio-is/sdk/runtime";
|
|
3
|
+
import { authenticateRequest } from "@webstudio-is/wsauth";
|
|
4
|
+
import { projectDomain } from "__CLIENT__";
|
|
5
|
+
import { getPageMeta, getRemixParams, getResources } from "__SERVER__";
|
|
6
|
+
import { sitemap } from "__SITEMAP__";
|
|
7
|
+
import { assets } from "__ASSETS__";
|
|
8
|
+
import { authRoutes } from "__AUTH__";
|
|
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
|
+
const customFetch: typeof fetch = (input, init) => {
|
|
29
|
+
if (typeof input !== "string") {
|
|
30
|
+
return fetch(input, init);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (isLocalResource(input, "sitemap.xml")) {
|
|
34
|
+
const response = new Response(JSON.stringify(sitemap));
|
|
35
|
+
response.headers.set("content-type", "application/json; charset=utf-8");
|
|
36
|
+
return Promise.resolve(response);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (isLocalResource(input, "current-date")) {
|
|
40
|
+
const now = new Date();
|
|
41
|
+
const startOfDay = new Date(
|
|
42
|
+
Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())
|
|
43
|
+
);
|
|
44
|
+
const data = {
|
|
45
|
+
iso: startOfDay.toISOString(),
|
|
46
|
+
year: startOfDay.getUTCFullYear(),
|
|
47
|
+
month: startOfDay.getUTCMonth() + 1,
|
|
48
|
+
day: startOfDay.getUTCDate(),
|
|
49
|
+
timestamp: startOfDay.getTime(),
|
|
50
|
+
};
|
|
51
|
+
const response = new Response(JSON.stringify(data));
|
|
52
|
+
response.headers.set("content-type", "application/json; charset=utf-8");
|
|
53
|
+
return Promise.resolve(response);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (isLocalResource(input, "assets")) {
|
|
57
|
+
const response = new Response(JSON.stringify(assets));
|
|
58
|
+
response.headers.set("content-type", "application/json; charset=utf-8");
|
|
59
|
+
return Promise.resolve(response);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return fetch(input, init);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const loader = async (arg: LoaderFunctionArgs) => {
|
|
66
|
+
const authRoute = authenticateProductionRequest(arg.request);
|
|
67
|
+
|
|
68
|
+
const url = new URL(arg.request.url);
|
|
69
|
+
const host =
|
|
70
|
+
arg.request.headers.get("x-forwarded-host") ||
|
|
71
|
+
arg.request.headers.get("host") ||
|
|
72
|
+
"";
|
|
73
|
+
url.host = host;
|
|
74
|
+
url.protocol = "https";
|
|
75
|
+
|
|
76
|
+
const params = getRemixParams(arg.params);
|
|
77
|
+
|
|
78
|
+
const system = {
|
|
79
|
+
params,
|
|
80
|
+
search: Object.fromEntries(url.searchParams),
|
|
81
|
+
origin: url.origin,
|
|
82
|
+
pathname: url.pathname,
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const resources = await loadResources(
|
|
86
|
+
customFetch,
|
|
87
|
+
getResources({ system }).data
|
|
88
|
+
);
|
|
89
|
+
const pageMeta = getPageMeta({ system, resources });
|
|
90
|
+
|
|
91
|
+
if (pageMeta.redirect) {
|
|
92
|
+
const status =
|
|
93
|
+
pageMeta.status === 301 || pageMeta.status === 302
|
|
94
|
+
? pageMeta.status
|
|
95
|
+
: 302;
|
|
96
|
+
return redirect(pageMeta.redirect, status);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return new Response(pageMeta.content ?? "", {
|
|
100
|
+
status: pageMeta.status,
|
|
101
|
+
headers: {
|
|
102
|
+
"Content-Type": "text/plain; charset=utf-8",
|
|
103
|
+
"Cache-Control":
|
|
104
|
+
authRoute === undefined ? "public, max-age=600" : "private, no-store",
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
};
|
|
@@ -1,15 +1,35 @@
|
|
|
1
1
|
import { renderToString } from "react-dom/server";
|
|
2
2
|
import { type LoaderFunctionArgs, redirect } from "react-router";
|
|
3
3
|
import { isLocalResource, loadResources } from "@webstudio-is/sdk/runtime";
|
|
4
|
+
import { authenticateRequest } from "@webstudio-is/wsauth";
|
|
4
5
|
import {
|
|
5
6
|
ReactSdkContext,
|
|
6
7
|
xmlNodeTagSuffix,
|
|
7
8
|
} from "@webstudio-is/react-sdk/runtime";
|
|
8
|
-
import { Page, breakpoints } from "__CLIENT__";
|
|
9
|
+
import { Page, breakpoints, projectDomain } from "__CLIENT__";
|
|
9
10
|
import { getPageMeta, getRemixParams, getResources } from "__SERVER__";
|
|
10
11
|
import { assetBaseUrl, imageLoader } from "__CONSTANTS__";
|
|
11
12
|
import { sitemap } from "__SITEMAP__";
|
|
12
13
|
import { assets } from "__ASSETS__";
|
|
14
|
+
import { authRoutes } from "__AUTH__";
|
|
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
|
+
};
|
|
13
33
|
|
|
14
34
|
const customFetch: typeof fetch = (input, init) => {
|
|
15
35
|
if (typeof input !== "string") {
|
|
@@ -51,6 +71,8 @@ const customFetch: typeof fetch = (input, init) => {
|
|
|
51
71
|
};
|
|
52
72
|
|
|
53
73
|
export const loader = async (arg: LoaderFunctionArgs) => {
|
|
74
|
+
const authRoute = authenticateProductionRequest(arg.request);
|
|
75
|
+
|
|
54
76
|
const url = new URL(arg.request.url);
|
|
55
77
|
const host =
|
|
56
78
|
arg.request.headers.get("x-forwarded-host") ||
|
|
@@ -108,6 +130,10 @@ export const loader = async (arg: LoaderFunctionArgs) => {
|
|
|
108
130
|
text = text.replaceAll(xmlNodeTagSuffix, "");
|
|
109
131
|
|
|
110
132
|
return new Response(`<?xml version="1.0" encoding="UTF-8"?>\n${text}`, {
|
|
111
|
-
headers: {
|
|
133
|
+
headers: {
|
|
134
|
+
"Content-Type": "application/xml",
|
|
135
|
+
"Cache-Control":
|
|
136
|
+
authRoute === undefined ? "public, max-age=600" : "private, no-store",
|
|
137
|
+
},
|
|
112
138
|
});
|
|
113
139
|
};
|
|
@@ -10,13 +10,14 @@
|
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@react-router/dev": "^7.5.3",
|
|
12
12
|
"@react-router/fs-routes": "^7.5.3",
|
|
13
|
-
"@webstudio-is/image": "0.
|
|
14
|
-
"@webstudio-is/react-sdk": "0.
|
|
15
|
-
"@webstudio-is/sdk": "0.
|
|
16
|
-
"@webstudio-is/sdk-components-animation": "0.
|
|
17
|
-
"@webstudio-is/sdk-components-react-radix": "0.
|
|
18
|
-
"@webstudio-is/sdk-components-react-router": "0.
|
|
19
|
-
"@webstudio-is/sdk-components-react": "0.
|
|
13
|
+
"@webstudio-is/image": "0.268.0",
|
|
14
|
+
"@webstudio-is/react-sdk": "0.268.0",
|
|
15
|
+
"@webstudio-is/sdk": "0.268.0",
|
|
16
|
+
"@webstudio-is/sdk-components-animation": "0.268.0",
|
|
17
|
+
"@webstudio-is/sdk-components-react-radix": "0.268.0",
|
|
18
|
+
"@webstudio-is/sdk-components-react-router": "0.268.0",
|
|
19
|
+
"@webstudio-is/sdk-components-react": "0.268.0",
|
|
20
|
+
"@webstudio-is/wsauth": "0.268.0",
|
|
20
21
|
"isbot": "^5.1.25",
|
|
21
22
|
"react": "18.3.0-canary-14898b6a9-20240318",
|
|
22
23
|
"react-dom": "18.3.0-canary-14898b6a9-20240318",
|
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
"typecheck": "tsgo --noEmit"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@webstudio-is/image": "0.
|
|
12
|
-
"@webstudio-is/react-sdk": "0.
|
|
13
|
-
"@webstudio-is/sdk": "0.
|
|
14
|
-
"@webstudio-is/sdk-components-react": "0.
|
|
15
|
-
"@webstudio-is/sdk-components-animation": "0.
|
|
16
|
-
"@webstudio-is/sdk-components-react-radix": "0.
|
|
11
|
+
"@webstudio-is/image": "0.268.0",
|
|
12
|
+
"@webstudio-is/react-sdk": "0.268.0",
|
|
13
|
+
"@webstudio-is/sdk": "0.268.0",
|
|
14
|
+
"@webstudio-is/sdk-components-react": "0.268.0",
|
|
15
|
+
"@webstudio-is/sdk-components-animation": "0.268.0",
|
|
16
|
+
"@webstudio-is/sdk-components-react-radix": "0.268.0",
|
|
17
17
|
"react": "18.3.0-canary-14898b6a9-20240318",
|
|
18
18
|
"react-dom": "18.3.0-canary-14898b6a9-20240318",
|
|
19
19
|
"vike": "^0.4.229"
|