prostgles-server 4.2.196 → 4.2.198
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/Auth/AuthHandler.d.ts +6 -5
- package/dist/Auth/AuthHandler.d.ts.map +1 -1
- package/dist/Auth/AuthHandler.js +22 -8
- package/dist/Auth/AuthHandler.js.map +1 -1
- package/dist/Auth/AuthTypes.d.ts +15 -13
- package/dist/Auth/AuthTypes.d.ts.map +1 -1
- package/dist/Auth/authProviders/setEmailProvider.d.ts.map +1 -1
- package/dist/Auth/authProviders/setEmailProvider.js +4 -5
- package/dist/Auth/authProviders/setEmailProvider.js.map +1 -1
- package/dist/Auth/endpoints/setCatchAllRequestHandler.d.ts +5 -0
- package/dist/Auth/endpoints/setCatchAllRequestHandler.d.ts.map +1 -0
- package/dist/Auth/endpoints/setCatchAllRequestHandler.js +95 -0
- package/dist/Auth/endpoints/setCatchAllRequestHandler.js.map +1 -0
- package/dist/Auth/endpoints/setConfirmEmailRequestHandler.d.ts +7 -0
- package/dist/Auth/endpoints/setConfirmEmailRequestHandler.d.ts.map +1 -0
- package/dist/Auth/endpoints/{getConfirmEmailRequestHandler.js → setConfirmEmailRequestHandler.js} +18 -9
- package/dist/Auth/endpoints/setConfirmEmailRequestHandler.js.map +1 -0
- package/dist/Auth/endpoints/setLoginRequestHandler.d.ts +4 -0
- package/dist/Auth/endpoints/setLoginRequestHandler.d.ts.map +1 -0
- package/dist/Auth/endpoints/setLoginRequestHandler.js +20 -0
- package/dist/Auth/endpoints/setLoginRequestHandler.js.map +1 -0
- package/dist/Auth/endpoints/setMagicLinkRequestHandler.d.ts +6 -0
- package/dist/Auth/endpoints/setMagicLinkRequestHandler.d.ts.map +1 -0
- package/dist/Auth/endpoints/setMagicLinkRequestHandler.js +36 -0
- package/dist/Auth/endpoints/setMagicLinkRequestHandler.js.map +1 -0
- package/dist/Auth/endpoints/setRegisterRequestHandler.d.ts +6 -0
- package/dist/Auth/endpoints/setRegisterRequestHandler.d.ts.map +1 -0
- package/dist/Auth/endpoints/{getRegisterRequestHandler.js → setRegisterRequestHandler.js} +5 -5
- package/dist/Auth/endpoints/setRegisterRequestHandler.js.map +1 -0
- package/dist/Auth/setupAuthRoutes.d.ts.map +1 -1
- package/dist/Auth/setupAuthRoutes.js +7 -125
- package/dist/Auth/setupAuthRoutes.js.map +1 -1
- package/dist/Auth/utils/getSidAndUserFromRequest.d.ts +8 -0
- package/dist/Auth/utils/getSidAndUserFromRequest.d.ts.map +1 -0
- package/dist/Auth/utils/{getUserFromRequest.js → getSidAndUserFromRequest.js} +15 -16
- package/dist/Auth/utils/getSidAndUserFromRequest.js.map +1 -0
- package/dist/DboBuilder/runSQL.d.ts.map +1 -1
- package/dist/DboBuilder/runSQL.js +4 -4
- package/dist/DboBuilder/runSQL.js.map +1 -1
- package/dist/Prostgles.js +1 -1
- package/dist/Prostgles.js.map +1 -1
- package/dist/PublishParser/PublishParser.d.ts +8 -8
- package/dist/PublishParser/PublishParser.d.ts.map +1 -1
- package/dist/PublishParser/PublishParser.js +6 -5
- package/dist/PublishParser/PublishParser.js.map +1 -1
- package/dist/PublishParser/getFileTableRules.d.ts +2 -2
- package/dist/PublishParser/getFileTableRules.d.ts.map +1 -1
- package/dist/PublishParser/getFileTableRules.js.map +1 -1
- package/dist/PublishParser/getSchemaFromPublish.d.ts +2 -2
- package/dist/PublishParser/getSchemaFromPublish.d.ts.map +1 -1
- package/dist/PublishParser/getSchemaFromPublish.js +2 -2
- package/dist/PublishParser/getSchemaFromPublish.js.map +1 -1
- package/dist/PublishParser/getTableRulesWithoutFileTable.d.ts +2 -2
- package/dist/PublishParser/getTableRulesWithoutFileTable.d.ts.map +1 -1
- package/dist/PublishParser/getTableRulesWithoutFileTable.js +1 -1
- package/dist/PublishParser/getTableRulesWithoutFileTable.js.map +1 -1
- package/dist/PublishParser/publishTypesAndUtils.d.ts +1 -1
- package/dist/PublishParser/publishTypesAndUtils.d.ts.map +1 -1
- package/dist/onSocketConnected.d.ts.map +1 -1
- package/dist/onSocketConnected.js +6 -2
- package/dist/onSocketConnected.js.map +1 -1
- package/dist/runClientRequest.d.ts.map +1 -1
- package/dist/runClientRequest.js +2 -2
- package/dist/runClientRequest.js.map +1 -1
- package/lib/Auth/AuthHandler.ts +27 -14
- package/lib/Auth/AuthTypes.ts +13 -17
- package/lib/Auth/authProviders/setEmailProvider.ts +5 -8
- package/lib/Auth/endpoints/setCatchAllRequestHandler.ts +107 -0
- package/lib/Auth/endpoints/setConfirmEmailRequestHandler.ts +50 -0
- package/lib/Auth/endpoints/setLoginRequestHandler.ts +18 -0
- package/lib/Auth/endpoints/setMagicLinkRequestHandler.ts +51 -0
- package/lib/Auth/endpoints/{getRegisterRequestHandler.ts → setRegisterRequestHandler.ts} +9 -6
- package/lib/Auth/setupAuthRoutes.ts +10 -149
- package/lib/Auth/utils/{getUserFromRequest.ts → getSidAndUserFromRequest.ts} +14 -13
- package/lib/DboBuilder/runSQL.ts +4 -5
- package/lib/Prostgles.ts +1 -1
- package/lib/PublishParser/PublishParser.ts +15 -13
- package/lib/PublishParser/getFileTableRules.ts +2 -2
- package/lib/PublishParser/getSchemaFromPublish.ts +4 -4
- package/lib/PublishParser/getTableRulesWithoutFileTable.ts +4 -3
- package/lib/PublishParser/publishTypesAndUtils.ts +1 -1
- package/lib/onSocketConnected.ts +7 -4
- package/lib/runClientRequest.ts +3 -11
- package/package.json +1 -1
- package/dist/Auth/endpoints/getConfirmEmailRequestHandler.d.ts +0 -7
- package/dist/Auth/endpoints/getConfirmEmailRequestHandler.d.ts.map +0 -1
- package/dist/Auth/endpoints/getConfirmEmailRequestHandler.js.map +0 -1
- package/dist/Auth/endpoints/getRegisterRequestHandler.d.ts +0 -7
- package/dist/Auth/endpoints/getRegisterRequestHandler.d.ts.map +0 -1
- package/dist/Auth/endpoints/getRegisterRequestHandler.js.map +0 -1
- package/dist/Auth/utils/getUserFromRequest.d.ts +0 -7
- package/dist/Auth/utils/getUserFromRequest.d.ts.map +0 -1
- package/dist/Auth/utils/getUserFromRequest.js.map +0 -1
- package/lib/Auth/endpoints/getConfirmEmailRequestHandler.ts +0 -39
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import e from "express";
|
|
2
|
+
import { AUTH_ROUTES_AND_PARAMS, AuthHandler, HTTP_FAIL_CODES } from "../AuthHandler";
|
|
3
|
+
import { LoginParams } from "../AuthTypes";
|
|
4
|
+
|
|
5
|
+
export function setLoginRequestHandler(this: AuthHandler, app: e.Express) {
|
|
6
|
+
app.post(AUTH_ROUTES_AND_PARAMS.login, async (req, res) => {
|
|
7
|
+
try {
|
|
8
|
+
const loginParams: LoginParams = {
|
|
9
|
+
type: "username",
|
|
10
|
+
...req.body,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
await this.loginThrottledAndSetCookie(req, res, loginParams);
|
|
14
|
+
} catch (error) {
|
|
15
|
+
res.status(HTTP_FAIL_CODES.BAD_REQUEST).json({ error });
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import e, { Response } from "express";
|
|
2
|
+
import { ExpressConfig, ExpressReq, SessionUser } from "../AuthTypes";
|
|
3
|
+
import { AuthResponse } from "prostgles-types";
|
|
4
|
+
import {
|
|
5
|
+
AUTH_ROUTES_AND_PARAMS,
|
|
6
|
+
AuthHandler,
|
|
7
|
+
getClientRequestIPsInfo,
|
|
8
|
+
HTTP_FAIL_CODES,
|
|
9
|
+
} from "../AuthHandler";
|
|
10
|
+
import { DBOFullyTyped } from "../../DBSchemaBuilder";
|
|
11
|
+
|
|
12
|
+
export function setMagicLinkRequestHandler(
|
|
13
|
+
this: AuthHandler,
|
|
14
|
+
onMagicLink: Required<ExpressConfig<void, SessionUser>>["onMagicLink"],
|
|
15
|
+
app: e.Express
|
|
16
|
+
) {
|
|
17
|
+
const result = async (
|
|
18
|
+
req: ExpressReq,
|
|
19
|
+
res: Response<AuthResponse.MagicLinkAuthFailure | AuthResponse.MagicLinkAuthSuccess>
|
|
20
|
+
) => {
|
|
21
|
+
const { id } = req.params;
|
|
22
|
+
|
|
23
|
+
if (typeof id !== "string" || !id) {
|
|
24
|
+
res
|
|
25
|
+
.status(HTTP_FAIL_CODES.BAD_REQUEST)
|
|
26
|
+
.json({ success: false, code: "something-went-wrong", message: "Invalid magic link" });
|
|
27
|
+
} else {
|
|
28
|
+
try {
|
|
29
|
+
const response = await this.throttledFunc(async () => {
|
|
30
|
+
return onMagicLink(
|
|
31
|
+
id,
|
|
32
|
+
this.dbo as DBOFullyTyped,
|
|
33
|
+
this.db,
|
|
34
|
+
getClientRequestIPsInfo({ httpReq: req, res })
|
|
35
|
+
);
|
|
36
|
+
});
|
|
37
|
+
if (!response.session) {
|
|
38
|
+
res.status(HTTP_FAIL_CODES.UNAUTHORIZED).json(response.response);
|
|
39
|
+
} else {
|
|
40
|
+
this.setCookieAndGoToReturnURLIFSet(response.session, { req, res });
|
|
41
|
+
}
|
|
42
|
+
} catch (_e) {
|
|
43
|
+
res
|
|
44
|
+
.status(HTTP_FAIL_CODES.UNAUTHORIZED)
|
|
45
|
+
.json({ success: false, code: "something-went-wrong" });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
app.get(AUTH_ROUTES_AND_PARAMS.magicLinksExpressRoute, result);
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Request, Response } from "express";
|
|
1
|
+
import e, { Request, Response } from "express";
|
|
2
2
|
import { AuthResponse } from "prostgles-types";
|
|
3
3
|
import { AUTH_ROUTES_AND_PARAMS, HTTP_FAIL_CODES } from "../AuthHandler";
|
|
4
4
|
import type { AuthRegistrationConfig } from "../AuthTypes";
|
|
@@ -11,10 +11,13 @@ type ReturnType =
|
|
|
11
11
|
| AuthResponse.PasswordRegisterFailure
|
|
12
12
|
| AuthResponse.PasswordRegisterSuccess;
|
|
13
13
|
|
|
14
|
-
export const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
export const setRegisterRequestHandler = (
|
|
15
|
+
{
|
|
16
|
+
email: emailAuthConfig,
|
|
17
|
+
websiteUrl,
|
|
18
|
+
}: Required<Pick<AuthRegistrationConfig<void>, "email" | "websiteUrl">>,
|
|
19
|
+
app: e.Express
|
|
20
|
+
) => {
|
|
18
21
|
const registerRequestHandler = async (req: Request, res: Response<ReturnType>) => {
|
|
19
22
|
const { username, password } = req.body;
|
|
20
23
|
const sendResponse = (response: ReturnType) => {
|
|
@@ -84,5 +87,5 @@ export const getRegisterRequestHandler = ({
|
|
|
84
87
|
}
|
|
85
88
|
};
|
|
86
89
|
|
|
87
|
-
|
|
90
|
+
app.post(AUTH_ROUTES_AND_PARAMS.emailRegistration, registerRequestHandler);
|
|
88
91
|
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { RequestHandler
|
|
2
|
-
import { AuthResponse } from "prostgles-types";
|
|
1
|
+
import { RequestHandler } from "express";
|
|
3
2
|
import { DBOFullyTyped } from "../DBSchemaBuilder";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { AuthHandler } from "./AuthHandler";
|
|
4
|
+
import { setCatchAllRequestHandler } from "./endpoints/setCatchAllRequestHandler";
|
|
5
|
+
import { setLoginRequestHandler } from "./endpoints/setLoginRequestHandler";
|
|
6
|
+
import { setMagicLinkRequestHandler } from "./endpoints/setMagicLinkRequestHandler";
|
|
6
7
|
import { setAuthProviders, upsertNamedExpressMiddleware } from "./setAuthProviders";
|
|
7
|
-
|
|
8
|
-
import { getReturnUrl } from "./utils/getReturnUrl";
|
|
8
|
+
|
|
9
9
|
export async function setupAuthRoutes(this: AuthHandler) {
|
|
10
10
|
const { login, expressConfig } = this.opts;
|
|
11
11
|
|
|
@@ -20,7 +20,7 @@ export async function setupAuthRoutes(this: AuthHandler) {
|
|
|
20
20
|
if (!expressConfig) {
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
23
|
-
const { app, publicRoutes = [],
|
|
23
|
+
const { app, publicRoutes = [], onMagicLink, use } = expressConfig;
|
|
24
24
|
if (publicRoutes.find((r) => typeof r !== "string" || !r)) {
|
|
25
25
|
throw "Invalid or empty string provided within publicRoutes ";
|
|
26
26
|
}
|
|
@@ -42,150 +42,11 @@ export async function setupAuthRoutes(this: AuthHandler) {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
if (onMagicLink) {
|
|
45
|
-
|
|
46
|
-
AUTH_ROUTES_AND_PARAMS.magicLinksExpressRoute,
|
|
47
|
-
async (
|
|
48
|
-
req: ExpressReq,
|
|
49
|
-
res: Response<AuthResponse.MagicLinkAuthFailure | AuthResponse.MagicLinkAuthSuccess>
|
|
50
|
-
) => {
|
|
51
|
-
const { id } = req.params;
|
|
52
|
-
|
|
53
|
-
if (typeof id !== "string" || !id) {
|
|
54
|
-
res
|
|
55
|
-
.status(HTTP_FAIL_CODES.BAD_REQUEST)
|
|
56
|
-
.json({ success: false, code: "something-went-wrong", message: "Invalid magic link" });
|
|
57
|
-
} else {
|
|
58
|
-
try {
|
|
59
|
-
const response = await this.throttledFunc(async () => {
|
|
60
|
-
return onMagicLink(
|
|
61
|
-
id,
|
|
62
|
-
this.dbo as any,
|
|
63
|
-
this.db,
|
|
64
|
-
getClientRequestIPsInfo({ httpReq: req, res })
|
|
65
|
-
);
|
|
66
|
-
});
|
|
67
|
-
if (!response.session) {
|
|
68
|
-
res.status(HTTP_FAIL_CODES.UNAUTHORIZED).json(response.response);
|
|
69
|
-
} else {
|
|
70
|
-
this.setCookieAndGoToReturnURLIFSet(response.session, { req, res });
|
|
71
|
-
}
|
|
72
|
-
} catch (e) {
|
|
73
|
-
res
|
|
74
|
-
.status(HTTP_FAIL_CODES.UNAUTHORIZED)
|
|
75
|
-
.json({ success: false, code: "something-went-wrong" });
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
);
|
|
45
|
+
setMagicLinkRequestHandler.bind(this)(onMagicLink, app);
|
|
80
46
|
}
|
|
81
47
|
|
|
82
|
-
|
|
83
|
-
try {
|
|
84
|
-
const loginParams: LoginParams = {
|
|
85
|
-
type: "username",
|
|
86
|
-
...req.body,
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
await this.loginThrottledAndSetCookie(req, res, loginParams);
|
|
90
|
-
} catch (error) {
|
|
91
|
-
res.status(HTTP_FAIL_CODES.BAD_REQUEST).json({ error });
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
const onLogout = async (req: ExpressReq, res: ExpressRes) => {
|
|
96
|
-
const sid = this.validateSid(req.cookies?.[this.sidKeyName]);
|
|
97
|
-
if (sid) {
|
|
98
|
-
try {
|
|
99
|
-
await this.throttledFunc(() => {
|
|
100
|
-
return this.opts.logout?.(req.cookies?.[this.sidKeyName], this.dbo as any, this.db);
|
|
101
|
-
});
|
|
102
|
-
} catch (err) {
|
|
103
|
-
console.error(err);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
res.redirect("/");
|
|
107
|
-
};
|
|
48
|
+
setLoginRequestHandler.bind(this)(app);
|
|
108
49
|
|
|
109
50
|
/* Redirect if not logged in and requesting non public content */
|
|
110
|
-
|
|
111
|
-
const clientReq: AuthClientRequest = { httpReq: req, res };
|
|
112
|
-
const getUser = async () => {
|
|
113
|
-
const userOrCode = await this.getUserAndHandleError(clientReq);
|
|
114
|
-
if (typeof userOrCode === "string") {
|
|
115
|
-
res.status(HTTP_FAIL_CODES.BAD_REQUEST).json({ success: false, code: userOrCode });
|
|
116
|
-
throw userOrCode;
|
|
117
|
-
}
|
|
118
|
-
return userOrCode;
|
|
119
|
-
};
|
|
120
|
-
const isLoggedInUser = async () => {
|
|
121
|
-
const userInfo = await getUser();
|
|
122
|
-
return !!userInfo?.user;
|
|
123
|
-
};
|
|
124
|
-
if (this.prostgles.restApi) {
|
|
125
|
-
if (
|
|
126
|
-
Object.values(this.prostgles.restApi.routes).some((restRoute) =>
|
|
127
|
-
this.matchesRoute(restRoute.split("/:")[0], req.path)
|
|
128
|
-
)
|
|
129
|
-
) {
|
|
130
|
-
next();
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
try {
|
|
135
|
-
const returnURL = getReturnUrl(req);
|
|
136
|
-
|
|
137
|
-
if (this.matchesRoute(AUTH_ROUTES_AND_PARAMS.logoutGetPath, req.path)) {
|
|
138
|
-
await onLogout(req, res);
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
if (this.matchesRoute(AUTH_ROUTES_AND_PARAMS.loginWithProvider, req.path)) {
|
|
143
|
-
next();
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Requesting a User route
|
|
148
|
-
*/
|
|
149
|
-
if (this.isUserRoute(req.path)) {
|
|
150
|
-
/* Check auth. Redirect to login if unauthorized */
|
|
151
|
-
const u = await isLoggedInUser();
|
|
152
|
-
if (!u) {
|
|
153
|
-
res.redirect(
|
|
154
|
-
`${AUTH_ROUTES_AND_PARAMS.login}?returnURL=${encodeURIComponent(req.originalUrl)}`
|
|
155
|
-
);
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/* If authorized and going to returnUrl then redirect. Otherwise serve file */
|
|
160
|
-
} else if (returnURL && (await isLoggedInUser())) {
|
|
161
|
-
res.redirect(returnURL);
|
|
162
|
-
return;
|
|
163
|
-
|
|
164
|
-
/** If Logged in and requesting login then redirect to main page */
|
|
165
|
-
} else if (
|
|
166
|
-
this.matchesRoute(AUTH_ROUTES_AND_PARAMS.login, req.path) &&
|
|
167
|
-
(await isLoggedInUser())
|
|
168
|
-
) {
|
|
169
|
-
res.redirect("/");
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
onGetRequestOK?.(req, res, {
|
|
174
|
-
getUser,
|
|
175
|
-
dbo: this.dbo as DBOFullyTyped,
|
|
176
|
-
db: this.db,
|
|
177
|
-
});
|
|
178
|
-
} catch (error) {
|
|
179
|
-
console.error(error);
|
|
180
|
-
const errorMessage =
|
|
181
|
-
typeof error === "string" ? error
|
|
182
|
-
: error instanceof Error ? error.message
|
|
183
|
-
: "";
|
|
184
|
-
res.status(HTTP_FAIL_CODES.BAD_REQUEST).json({
|
|
185
|
-
error:
|
|
186
|
-
"Something went wrong when processing your request" +
|
|
187
|
-
(errorMessage ? ": " + errorMessage : ""),
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
});
|
|
51
|
+
setCatchAllRequestHandler.bind(this)(app);
|
|
191
52
|
}
|
|
@@ -1,21 +1,22 @@
|
|
|
1
|
+
import { DBOFullyTyped } from "../../DBSchemaBuilder";
|
|
1
2
|
import { AuthHandler, getClientRequestIPsInfo } from "../AuthHandler";
|
|
2
3
|
import { AuthClientRequest, AuthResultWithSID } from "../AuthTypes";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
|
-
* For a given sid return the user data if available
|
|
6
|
+
* For a given sid return the user data if available using the auth handler's getUser method.
|
|
7
|
+
* Use socket session cache if configured in Auth
|
|
6
8
|
*/
|
|
7
|
-
export async function
|
|
9
|
+
export async function getSidAndUserFromRequest(
|
|
8
10
|
this: AuthHandler,
|
|
9
|
-
|
|
11
|
+
clientReq: AuthClientRequest
|
|
10
12
|
): Promise<AuthResultWithSID> {
|
|
11
|
-
if (!maybeClientReq) return undefined;
|
|
12
13
|
/**
|
|
13
14
|
* Get cached session if available
|
|
14
15
|
*/
|
|
15
16
|
const getSession = this.opts.cacheSession?.getSession;
|
|
16
|
-
if (
|
|
17
|
-
const { session, user, clientUser } =
|
|
18
|
-
const isValid = this.isNonExpiredSocketSession(
|
|
17
|
+
if (clientReq.socket && getSession && clientReq.socket.__prglCache) {
|
|
18
|
+
const { session, user, clientUser } = clientReq.socket.__prglCache;
|
|
19
|
+
const isValid = this.isNonExpiredSocketSession(clientReq.socket, session);
|
|
19
20
|
if (isValid) {
|
|
20
21
|
return {
|
|
21
22
|
sid: session.sid,
|
|
@@ -35,17 +36,17 @@ export async function getUserFromRequest(
|
|
|
35
36
|
const result = await this.throttledFunc(async () => {
|
|
36
37
|
const { getUser } = this.opts;
|
|
37
38
|
|
|
38
|
-
const sid = this.getSID(
|
|
39
|
+
const sid = this.getSID(clientReq);
|
|
39
40
|
const clientInfoOrErr =
|
|
40
41
|
!sid ? undefined : (
|
|
41
|
-
await getUser(sid, this.dbo as
|
|
42
|
+
await getUser(sid, this.dbo as DBOFullyTyped, this.db, getClientRequestIPsInfo(clientReq))
|
|
42
43
|
);
|
|
43
44
|
if (typeof clientInfoOrErr === "string") throw clientInfoOrErr;
|
|
44
45
|
const clientInfo = clientInfoOrErr;
|
|
45
|
-
if (getSession &&
|
|
46
|
+
if (getSession && clientReq.socket) {
|
|
46
47
|
const session = await getSession(sid, this.dbo as any, this.db);
|
|
47
48
|
if (session && session.expires && clientInfo?.user) {
|
|
48
|
-
|
|
49
|
+
clientReq.socket.__prglCache = {
|
|
49
50
|
session,
|
|
50
51
|
user: clientInfo.user,
|
|
51
52
|
clientUser: clientInfo.clientUser,
|
|
@@ -58,14 +59,14 @@ export async function getUserFromRequest(
|
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
return { sid };
|
|
61
|
-
},
|
|
62
|
+
}, 100);
|
|
62
63
|
|
|
63
64
|
await this.prostgles.opts.onLog?.({
|
|
64
65
|
type: "auth",
|
|
65
66
|
command: "getClientInfo",
|
|
66
67
|
duration: Date.now() - authStart,
|
|
67
68
|
sid: result.sid,
|
|
68
|
-
socketId:
|
|
69
|
+
socketId: clientReq.socket?.id,
|
|
69
70
|
});
|
|
70
71
|
return result;
|
|
71
72
|
}
|
package/lib/DboBuilder/runSQL.ts
CHANGED
|
@@ -192,11 +192,10 @@ export const canRunSQL = async (
|
|
|
192
192
|
clientReq: AuthClientRequest | undefined
|
|
193
193
|
): Promise<boolean> => {
|
|
194
194
|
if (!clientReq) return true;
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
return Boolean((res && typeof res === "boolean") || res === "*");
|
|
195
|
+
const publishParams = await prostgles.publishParser?.getPublishParams(clientReq, undefined);
|
|
196
|
+
//@ts-ignore union type that is too complex to represent.
|
|
197
|
+
const publishResult = publishParams && (await prostgles.opts.publishRawSQL?.(publishParams));
|
|
198
|
+
return Boolean((publishResult && typeof publishResult === "boolean") || publishResult === "*");
|
|
200
199
|
};
|
|
201
200
|
|
|
202
201
|
export const canCreateTables = async (db: DB): Promise<boolean> => {
|
package/lib/Prostgles.ts
CHANGED
|
@@ -413,7 +413,7 @@ export class Prostgles {
|
|
|
413
413
|
{ type: "socket" as const, ...clientReq }
|
|
414
414
|
: { type: "http" as const, ...clientReq };
|
|
415
415
|
|
|
416
|
-
const userData = await this.authHandler?.
|
|
416
|
+
const userData = await this.authHandler?.getSidAndUserFromRequest(clientInfo);
|
|
417
417
|
const { publishParser } = this;
|
|
418
418
|
let fullSchema: Awaited<ReturnType<PublishParser["getSchemaFromPublish"]>> | undefined;
|
|
419
419
|
let publishValidationError;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Method, getObjectEntries, isObject } from "prostgles-types";
|
|
2
|
-
import { AuthClientRequest,
|
|
3
|
-
import { PublishFullyTyped } from "../DBSchemaBuilder";
|
|
2
|
+
import { AuthClientRequest, AuthResultWithSID, SessionUser } from "../Auth/AuthTypes";
|
|
3
|
+
import { DBOFullyTyped, PublishFullyTyped } from "../DBSchemaBuilder";
|
|
4
4
|
import { DB, DBHandlerServer, Prostgles } from "../Prostgles";
|
|
5
5
|
import { ProstglesInitOptions } from "../ProstglesTypes";
|
|
6
6
|
import { VoidFunction } from "../SchemaWatch/SchemaWatch";
|
|
@@ -39,11 +39,12 @@ export class PublishParser {
|
|
|
39
39
|
|
|
40
40
|
async getPublishParams(
|
|
41
41
|
clientReq: AuthClientRequest,
|
|
42
|
-
clientInfo
|
|
42
|
+
clientInfo: AuthResultWithSID | undefined
|
|
43
43
|
): Promise<PublishParams> {
|
|
44
44
|
return {
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
sid: undefined,
|
|
46
|
+
...(clientInfo ?? (await this.prostgles.authHandler?.getSidAndUserFromRequest(clientReq))),
|
|
47
|
+
dbo: this.dbo as DBOFullyTyped,
|
|
47
48
|
db: this.db,
|
|
48
49
|
clientReq,
|
|
49
50
|
tables: this.prostgles.dboBuilder.tables,
|
|
@@ -52,7 +53,7 @@ export class PublishParser {
|
|
|
52
53
|
|
|
53
54
|
async getAllowedMethods(
|
|
54
55
|
clientReq: AuthClientRequest,
|
|
55
|
-
userData:
|
|
56
|
+
userData: AuthResultWithSID | undefined
|
|
56
57
|
): Promise<{ [key: string]: Method }> {
|
|
57
58
|
const methods: { [key: string]: Method } = {};
|
|
58
59
|
|
|
@@ -81,9 +82,9 @@ export class PublishParser {
|
|
|
81
82
|
/**
|
|
82
83
|
* Parses the first level of publish. (If false then nothing if * then all tables and views)
|
|
83
84
|
*/
|
|
84
|
-
async
|
|
85
|
+
async getPublishAsObject(
|
|
85
86
|
clientReq: AuthClientRequest,
|
|
86
|
-
clientInfo:
|
|
87
|
+
clientInfo: AuthResultWithSID | undefined
|
|
87
88
|
): Promise<PublishFullyTyped | undefined> {
|
|
88
89
|
const publishParams = await this.getPublishParams(clientReq, clientInfo);
|
|
89
90
|
const _publish = await applyParamsIfFunc(this.publish, publishParams);
|
|
@@ -104,14 +105,15 @@ export class PublishParser {
|
|
|
104
105
|
command,
|
|
105
106
|
clientReq,
|
|
106
107
|
}: DboTableCommand): Promise<TableRule> {
|
|
107
|
-
const clientInfo =
|
|
108
|
+
const clientInfo =
|
|
109
|
+
clientReq && (await this.prostgles.authHandler?.getSidAndUserFromRequest(clientReq));
|
|
108
110
|
const rules = await this.getValidatedRequestRule({ tableName, command, clientReq }, clientInfo);
|
|
109
111
|
return rules;
|
|
110
112
|
}
|
|
111
113
|
|
|
112
114
|
async getValidatedRequestRule(
|
|
113
115
|
{ tableName, command, clientReq }: DboTableCommand,
|
|
114
|
-
clientInfo:
|
|
116
|
+
clientInfo: AuthResultWithSID | undefined
|
|
115
117
|
): Promise<TableRule> {
|
|
116
118
|
if (!command || !tableName) throw "command OR tableName are missing";
|
|
117
119
|
|
|
@@ -166,10 +168,10 @@ export class PublishParser {
|
|
|
166
168
|
|
|
167
169
|
async getTableRules(
|
|
168
170
|
args: DboTable,
|
|
169
|
-
clientInfo:
|
|
171
|
+
clientInfo: AuthResultWithSID | undefined
|
|
170
172
|
): Promise<ParsedPublishTable | undefined> {
|
|
173
|
+
const fileTablePublishRules = await this.getTableRulesWithoutFileTable(args, clientInfo);
|
|
171
174
|
if (this.dbo[args.tableName]?.is_media) {
|
|
172
|
-
const fileTablePublishRules = await this.getTableRulesWithoutFileTable(args, clientInfo);
|
|
173
175
|
const { rules } = await getFileTableRules.bind(this)(
|
|
174
176
|
args.tableName,
|
|
175
177
|
fileTablePublishRules,
|
|
@@ -179,7 +181,7 @@ export class PublishParser {
|
|
|
179
181
|
return rules;
|
|
180
182
|
}
|
|
181
183
|
|
|
182
|
-
return
|
|
184
|
+
return fileTablePublishRules;
|
|
183
185
|
}
|
|
184
186
|
|
|
185
187
|
getTableRulesWithoutFileTable = getTableRulesWithoutFileTable.bind(this);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AnyObject, FullFilter, isDefined } from "prostgles-types";
|
|
2
|
-
import { AuthClientRequest,
|
|
2
|
+
import { AuthClientRequest, AuthResultWithSID } from "../Auth/AuthTypes";
|
|
3
3
|
import { parseFieldFilter } from "../DboBuilder/ViewHandler/parseFieldFilter";
|
|
4
4
|
import { PublishParser } from "./PublishParser";
|
|
5
5
|
import { ParsedPublishTable, UpdateRule } from "./publishTypesAndUtils";
|
|
@@ -17,7 +17,7 @@ export async function getFileTableRules(
|
|
|
17
17
|
fileTableName: string,
|
|
18
18
|
fileTablePublishRules: ParsedPublishTable | undefined,
|
|
19
19
|
clientReq: AuthClientRequest | undefined,
|
|
20
|
-
clientInfo:
|
|
20
|
+
clientInfo: AuthResultWithSID | undefined
|
|
21
21
|
) {
|
|
22
22
|
const forcedDeleteFilters: FullFilter<AnyObject, void>[] = [];
|
|
23
23
|
const forcedSelectFilters: FullFilter<AnyObject, void>[] = [];
|
|
@@ -7,13 +7,13 @@ import {
|
|
|
7
7
|
TableSchemaErrors,
|
|
8
8
|
TableSchemaForClient,
|
|
9
9
|
} from "prostgles-types";
|
|
10
|
-
import { AuthClientRequest,
|
|
10
|
+
import { AuthClientRequest, AuthResultWithSID } from "../Auth/AuthTypes";
|
|
11
11
|
import { getErrorAsObject } from "../DboBuilder/DboBuilder";
|
|
12
12
|
import { TABLE_METHODS } from "../Prostgles";
|
|
13
13
|
import { PublishObject, PublishParser } from "./PublishParser";
|
|
14
14
|
|
|
15
15
|
type Args = AuthClientRequest & {
|
|
16
|
-
userData:
|
|
16
|
+
userData: AuthResultWithSID | undefined;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
export async function getSchemaFromPublish(
|
|
@@ -31,11 +31,11 @@ export async function getSchemaFromPublish(
|
|
|
31
31
|
try {
|
|
32
32
|
/* Publish tables and views based on socket */
|
|
33
33
|
const clientInfo =
|
|
34
|
-
userData ?? (await this.prostgles.authHandler?.
|
|
34
|
+
userData ?? (await this.prostgles.authHandler?.getSidAndUserFromRequest(clientReq));
|
|
35
35
|
|
|
36
36
|
let _publish: PublishObject | undefined;
|
|
37
37
|
try {
|
|
38
|
-
_publish = await this.
|
|
38
|
+
_publish = await this.getPublishAsObject(clientReq, clientInfo);
|
|
39
39
|
} catch (err) {
|
|
40
40
|
console.error("Error within then Publish function ", err);
|
|
41
41
|
throw err;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getKeys, isObject } from "prostgles-types";
|
|
2
|
-
import { AuthResult } from "../Auth/AuthTypes";
|
|
2
|
+
import { AuthResult, AuthResultWithSID } from "../Auth/AuthTypes";
|
|
3
3
|
import { TableHandler } from "../DboBuilder/TableHandler/TableHandler";
|
|
4
4
|
import { ViewHandler } from "../DboBuilder/ViewHandler/ViewHandler";
|
|
5
5
|
import { DEFAULT_SYNC_BATCH_SIZE } from "../PubSubManager/PubSubManager";
|
|
@@ -17,12 +17,13 @@ import {
|
|
|
17
17
|
export async function getTableRulesWithoutFileTable(
|
|
18
18
|
this: PublishParser,
|
|
19
19
|
{ tableName, clientReq }: DboTable,
|
|
20
|
-
clientInfo
|
|
20
|
+
clientInfo: AuthResultWithSID | undefined,
|
|
21
21
|
overridenPublish?: PublishObject
|
|
22
22
|
): Promise<ParsedPublishTable | undefined> {
|
|
23
23
|
if (!tableName) throw new Error("publish OR socket OR dbo OR tableName are missing");
|
|
24
24
|
|
|
25
|
-
const publish =
|
|
25
|
+
const publish =
|
|
26
|
+
overridenPublish ?? (clientReq && (await this.getPublishAsObject(clientReq, clientInfo)));
|
|
26
27
|
|
|
27
28
|
const rawTableRule = publish?.[tableName];
|
|
28
29
|
if (!rawTableRule || (isObject(rawTableRule) && Object.values(rawTableRule).every((v) => !v))) {
|
|
@@ -432,7 +432,7 @@ export type DbTableInfo = {
|
|
|
432
432
|
columns: TableSchemaColumn[];
|
|
433
433
|
};
|
|
434
434
|
export type PublishParams<S = void, SUser extends SessionUser = SessionUser> = {
|
|
435
|
-
sid
|
|
435
|
+
sid: string | undefined;
|
|
436
436
|
dbo: DBOFullyTyped<S>;
|
|
437
437
|
db: DB;
|
|
438
438
|
user?: SUser["user"];
|
package/lib/onSocketConnected.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { Prostgles, TABLE_METHODS } from "./Prostgles";
|
|
|
3
3
|
import { PRGLIOSocket } from "./DboBuilder/DboBuilderTypes";
|
|
4
4
|
import { runClientMethod, runClientRequest } from "./runClientRequest";
|
|
5
5
|
import { getErrorAsObject } from "./DboBuilder/dboBuilderUtils";
|
|
6
|
+
import { DBOFullyTyped } from "./DBSchemaBuilder";
|
|
6
7
|
|
|
7
8
|
export async function onSocketConnected(this: Prostgles, socket: PRGLIOSocket) {
|
|
8
9
|
if (this.destroyed) {
|
|
@@ -26,11 +27,12 @@ export async function onSocketConnected(this: Prostgles, socket: PRGLIOSocket) {
|
|
|
26
27
|
if (this.opts.onSocketConnect) {
|
|
27
28
|
try {
|
|
28
29
|
const getUser = async () => {
|
|
29
|
-
|
|
30
|
+
if (!this.authHandler) throw "authHandler missing";
|
|
31
|
+
return await this.authHandler.getSidAndUserFromRequest({ socket });
|
|
30
32
|
};
|
|
31
33
|
await this.opts.onSocketConnect({
|
|
32
34
|
socket,
|
|
33
|
-
dbo: dbo as
|
|
35
|
+
dbo: dbo as DBOFullyTyped,
|
|
34
36
|
db,
|
|
35
37
|
getUser,
|
|
36
38
|
});
|
|
@@ -79,9 +81,10 @@ export async function onSocketConnected(this: Prostgles, socket: PRGLIOSocket) {
|
|
|
79
81
|
|
|
80
82
|
if (this.opts.onSocketDisconnect) {
|
|
81
83
|
const getUser = async () => {
|
|
82
|
-
|
|
84
|
+
if (!this.authHandler) throw "authHandler missing";
|
|
85
|
+
return await this.authHandler.getSidAndUserFromRequest({ socket });
|
|
83
86
|
};
|
|
84
|
-
this.opts.onSocketDisconnect({ socket, dbo: dbo as
|
|
87
|
+
this.opts.onSocketDisconnect({ socket, dbo: dbo as DBOFullyTyped, db, getUser });
|
|
85
88
|
}
|
|
86
89
|
});
|
|
87
90
|
|
package/lib/runClientRequest.ts
CHANGED
|
@@ -1,12 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AnyObject,
|
|
3
|
-
SQLOptions,
|
|
4
|
-
SQLRequest,
|
|
5
|
-
TableHandler,
|
|
6
|
-
UserLike,
|
|
7
|
-
getKeys,
|
|
8
|
-
pickKeys,
|
|
9
|
-
} from "prostgles-types";
|
|
1
|
+
import { SQLRequest, TableHandler, UserLike, getKeys, pickKeys } from "prostgles-types";
|
|
10
2
|
import { AuthClientRequest } from "./Auth/AuthTypes";
|
|
11
3
|
import { LocalParams } from "./DboBuilder/DboBuilder";
|
|
12
4
|
import { TableHandler as TableHandlerServer } from "./DboBuilder/TableHandler/TableHandler";
|
|
@@ -77,7 +69,7 @@ export const runClientRequest = async function (
|
|
|
77
69
|
);
|
|
78
70
|
}
|
|
79
71
|
|
|
80
|
-
const clientInfo = await this.authHandler?.
|
|
72
|
+
const clientInfo = await this.authHandler?.getSidAndUserFromRequest(clientReq);
|
|
81
73
|
const validRules = await this.publishParser.getValidatedRequestRule(
|
|
82
74
|
{ tableName, command, clientReq },
|
|
83
75
|
clientInfo
|
|
@@ -147,7 +139,7 @@ export const clientCanRunSqlRequest = async function (
|
|
|
147
139
|
if (!this.authHandler) {
|
|
148
140
|
throw "authHandler missing";
|
|
149
141
|
}
|
|
150
|
-
const publishParams = await this.publishParser?.getPublishParams(clientReq);
|
|
142
|
+
const publishParams = await this.publishParser?.getPublishParams(clientReq, undefined);
|
|
151
143
|
const res = publishParams && (await this.opts.publishRawSQL?.(publishParams));
|
|
152
144
|
return Boolean((res && typeof res === "boolean") || res === "*");
|
|
153
145
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { Request, Response } from "express";
|
|
2
|
-
import { AuthResponse } from "prostgles-types";
|
|
3
|
-
import { AuthRegistrationConfig } from "../AuthTypes";
|
|
4
|
-
export declare const getConfirmEmailRequestHandler: (emailAuthConfig: Extract<Required<AuthRegistrationConfig<void>>["email"], {
|
|
5
|
-
signupType: "withPassword";
|
|
6
|
-
}>) => (req: Request, res: Response<AuthResponse.PasswordRegisterSuccess | AuthResponse.PasswordRegisterFailure | AuthResponse.AuthSuccess>) => Promise<Response<AuthResponse.PasswordRegisterSuccess | AuthResponse.PasswordRegisterFailure | AuthResponse.AuthSuccess, Record<string, any>> | undefined>;
|
|
7
|
-
//# sourceMappingURL=getConfirmEmailRequestHandler.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"getConfirmEmailRequestHandler.d.ts","sourceRoot":"","sources":["../../../lib/Auth/endpoints/getConfirmEmailRequestHandler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAGtD,eAAO,MAAM,6BAA6B,oBACvB,QACf,SAAS,uBAAuB,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,EAC/C;IAAE,UAAU,EAAE,cAAc,CAAA;CAAE,CAC/B,WAGM,OAAO,OACP,SACD,aAAa,uBAAuB,GACpC,aAAa,uBAAuB,GACpC,aAAa,WAAW,CAC3B,+JAoBJ,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"getConfirmEmailRequestHandler.js","sourceRoot":"","sources":["../../../lib/Auth/endpoints/getConfirmEmailRequestHandler.ts"],"names":[],"mappings":";;;AAEA,gDAAiD;AAEjD,8EAA2E;AAEpE,MAAM,6BAA6B,GAAG,CAC3C,eAGC,EACD,EAAE;IACF,OAAO,KAAK,EACV,GAAY,EACZ,GAIC,EACD,EAAE;QACF,MAAM,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC;YACH,IAAI,CAAC,EAAE,IAAI,OAAO,EAAE,KAAK,QAAQ,EAAE,CAAC;gBAClC,OAAO,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,sBAAsB,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC;YAC7F,CAAC;YACD,MAAM,EAAE,OAAO,EAAE,GAAG,UAAU,EAAE,GAAG,IAAA,iDAAuB,EAAC,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;YAClF,MAAM,eAAe,CAAC,mBAAmB,CAAC;gBACxC,gBAAgB,EAAE,EAAE;gBACpB,UAAU;gBACV,GAAG,EAAE,OAAO;aACb,CAAC,CAAC;YACH,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC,CAAC;QAC1D,CAAC;QAAC,OAAO,EAAE,EAAE,CAAC;YACZ,GAAG;iBACA,MAAM,CAAC,6BAAe,CAAC,WAAW,CAAC;iBACnC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,yBAAyB,EAAE,CAAC,CAAC;QACxF,CAAC;IACH,CAAC,CAAC;AACJ,CAAC,CAAC;AAhCW,QAAA,6BAA6B,iCAgCxC"}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { Request, Response } from "express";
|
|
2
|
-
import { AuthResponse } from "prostgles-types";
|
|
3
|
-
import type { AuthRegistrationConfig } from "../AuthTypes";
|
|
4
|
-
type ReturnType = AuthResponse.MagicLinkAuthFailure | AuthResponse.MagicLinkAuthSuccess | AuthResponse.PasswordRegisterFailure | AuthResponse.PasswordRegisterSuccess;
|
|
5
|
-
export declare const getRegisterRequestHandler: ({ email: emailAuthConfig, websiteUrl, }: Required<Pick<AuthRegistrationConfig<void>, "email" | "websiteUrl">>) => (req: Request, res: Response<ReturnType>) => Promise<void>;
|
|
6
|
-
export {};
|
|
7
|
-
//# sourceMappingURL=getRegisterRequestHandler.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"getRegisterRequestHandler.d.ts","sourceRoot":"","sources":["../../../lib/Auth/endpoints/getRegisterRequestHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAI3D,KAAK,UAAU,GACX,YAAY,CAAC,oBAAoB,GACjC,YAAY,CAAC,oBAAoB,GACjC,YAAY,CAAC,uBAAuB,GACpC,YAAY,CAAC,uBAAuB,CAAC;AAEzC,eAAO,MAAM,yBAAyB,4CAGnC,SAAS,KAAK,uBAAuB,IAAI,CAAC,EAAE,OAAO,GAAG,YAAY,CAAC,CAAC,WAC1B,OAAO,OAAO,SAAS,UAAU,CAAC,kBAsE9E,CAAC"}
|