prostgles-server 4.2.155 → 4.2.157
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 +2 -0
- package/dist/Auth/AuthHandler.d.ts.map +1 -1
- package/dist/Auth/AuthHandler.js +4 -2
- package/dist/Auth/AuthHandler.js.map +1 -1
- package/dist/Auth/AuthTypes.d.ts +63 -16
- package/dist/Auth/AuthTypes.d.ts.map +1 -1
- package/dist/Auth/sendEmail.d.ts +7 -0
- package/dist/Auth/sendEmail.d.ts.map +1 -0
- package/dist/Auth/sendEmail.js +69 -0
- package/dist/Auth/sendEmail.js.map +1 -0
- package/dist/Auth/setAuthProviders.d.ts +3 -3
- package/dist/Auth/setAuthProviders.d.ts.map +1 -1
- package/dist/Auth/setAuthProviders.js +29 -51
- package/dist/Auth/setAuthProviders.js.map +1 -1
- package/dist/Auth/setEmailProvider.d.ts +4 -0
- package/dist/Auth/setEmailProvider.d.ts.map +1 -0
- package/dist/Auth/setEmailProvider.js +66 -0
- package/dist/Auth/setEmailProvider.js.map +1 -0
- package/lib/Auth/AuthHandler.ts +4 -2
- package/lib/Auth/AuthTypes.ts +55 -18
- package/lib/Auth/sendEmail.ts +83 -0
- package/lib/Auth/setAuthProviders.ts +41 -64
- package/lib/Auth/setEmailProvider.ts +63 -0
- package/package.json +11 -7
- package/tests/client/package-lock.json +8 -2689
- package/tests/client/package.json +1 -1
- package/tests/server/index.ts +5 -3
- package/tests/server/package-lock.json +16 -8
package/lib/Auth/AuthTypes.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type { StrategyOptions as GoogleStrategy, Profile as GoogleProfile } from
|
|
|
8
8
|
import type { StrategyOptions as GitHubStrategy, Profile as GitHubProfile } from "passport-github2";
|
|
9
9
|
import type { MicrosoftStrategyOptions } from "passport-microsoft";
|
|
10
10
|
import type { StrategyOptions as FacebookStrategy, Profile as FacebookProfile } from "passport-facebook";
|
|
11
|
+
import Mail from "nodemailer/lib/mailer";
|
|
11
12
|
|
|
12
13
|
type Awaitable<T> = T | Promise<T>;
|
|
13
14
|
|
|
@@ -49,30 +50,62 @@ type ThirdPartyProviders = {
|
|
|
49
50
|
};
|
|
50
51
|
};
|
|
51
52
|
|
|
52
|
-
type SMTPConfig = {
|
|
53
|
-
type: "
|
|
53
|
+
export type SMTPConfig = {
|
|
54
|
+
type: "smtp";
|
|
54
55
|
host: string;
|
|
55
56
|
port: number;
|
|
56
57
|
secure: boolean;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
user: string;
|
|
59
|
+
pass: string;
|
|
60
|
+
} | {
|
|
61
|
+
type: "aws-ses";
|
|
62
|
+
region: string;
|
|
63
|
+
accessKeyId: string;
|
|
64
|
+
secretAccessKey: string;
|
|
65
|
+
/**
|
|
66
|
+
* Sending rate per second
|
|
67
|
+
* Defaults to 1
|
|
68
|
+
*/
|
|
69
|
+
sendingRate?: number;
|
|
61
70
|
}
|
|
62
71
|
|
|
63
|
-
type
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
* If provided, the user will be required to confirm their email address
|
|
71
|
-
*/
|
|
72
|
-
smtp?: SMTPConfig;
|
|
73
|
-
};
|
|
72
|
+
export type Email = {
|
|
73
|
+
from: string;
|
|
74
|
+
to: string;
|
|
75
|
+
subject: string;
|
|
76
|
+
html: string;
|
|
77
|
+
text?: string;
|
|
78
|
+
attachments?: { filename: string; content: string; }[] | Mail.Attachment[];
|
|
74
79
|
}
|
|
75
80
|
|
|
81
|
+
type EmailWithoutTo = Omit<Email, "to">;
|
|
82
|
+
|
|
83
|
+
type EmailProvider =
|
|
84
|
+
| {
|
|
85
|
+
signupType: "withMagicLink";
|
|
86
|
+
onRegistered: (data: { username: string; }) => void | Promise<void>;
|
|
87
|
+
emailMagicLink: {
|
|
88
|
+
onSend: (data: { email: string; magicLinkPath: string; }) => EmailWithoutTo | Promise<EmailWithoutTo>;
|
|
89
|
+
smtp: SMTPConfig;
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
| {
|
|
93
|
+
signupType: "withPassword";
|
|
94
|
+
onRegistered: (data: { username: string; password: string; }) => void | Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Defaults to 8
|
|
97
|
+
*/
|
|
98
|
+
minPasswordLength: number;
|
|
99
|
+
/**
|
|
100
|
+
* If provided, the user will be required to confirm their email address
|
|
101
|
+
*/
|
|
102
|
+
emailConfirmation?: {
|
|
103
|
+
onSend: (data: { email: string; confirmationUrlPath: string; }) => EmailWithoutTo | Promise<EmailWithoutTo>;
|
|
104
|
+
smtp: SMTPConfig;
|
|
105
|
+
onConfirmed: (data: { confirmationUrlPath: string; }) => void | Promise<void>;
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
|
|
76
109
|
export type AuthProviderUserData =
|
|
77
110
|
| {
|
|
78
111
|
provider: "google";
|
|
@@ -109,7 +142,11 @@ export type RegistrationData =
|
|
|
109
142
|
}
|
|
110
143
|
| AuthProviderUserData;
|
|
111
144
|
|
|
112
|
-
export type AuthRegistrationConfig<S> =
|
|
145
|
+
export type AuthRegistrationConfig<S> = {
|
|
146
|
+
email?: EmailProvider;
|
|
147
|
+
|
|
148
|
+
OAuthProviders?: ThirdPartyProviders;
|
|
149
|
+
|
|
113
150
|
/**
|
|
114
151
|
* Required for social login callback
|
|
115
152
|
*/
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Email, SMTPConfig } from "./AuthTypes";
|
|
2
|
+
import nodemailer from "nodemailer";
|
|
3
|
+
import aws from "@aws-sdk/client-ses";
|
|
4
|
+
import SESTransport from "nodemailer/lib/ses-transport";
|
|
5
|
+
|
|
6
|
+
type SESTransporter = nodemailer.Transporter<SESTransport.SentMessageInfo, SESTransport.Options>;
|
|
7
|
+
type SMTPTransporter = nodemailer.Transporter<nodemailer.SentMessageInfo, nodemailer.TransportOptions>;
|
|
8
|
+
type Transporter = SESTransporter | SMTPTransporter;
|
|
9
|
+
|
|
10
|
+
const transporterCache: Map<string, Transporter> = new Map();
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Allows sending emails using nodemailer default config or AWS SES
|
|
14
|
+
* https://www.nodemailer.com/transports/ses/
|
|
15
|
+
*/
|
|
16
|
+
export const sendEmail = (smptConfig: SMTPConfig, email: Email) => {
|
|
17
|
+
const configStr = JSON.stringify(smptConfig);
|
|
18
|
+
const transporter = transporterCache.get(configStr) ?? getTransporter(smptConfig);
|
|
19
|
+
if(!transporterCache.has(configStr)){
|
|
20
|
+
transporterCache.set(configStr, transporter);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return send(transporter, email);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const getTransporter = (smptConfig: SMTPConfig) => {
|
|
27
|
+
let transporter: Transporter | undefined;
|
|
28
|
+
if(smptConfig.type === "aws-ses"){
|
|
29
|
+
const {
|
|
30
|
+
region,
|
|
31
|
+
accessKeyId,
|
|
32
|
+
secretAccessKey,
|
|
33
|
+
/**
|
|
34
|
+
* max 1 messages/second
|
|
35
|
+
*/
|
|
36
|
+
sendingRate = 1
|
|
37
|
+
} = smptConfig;
|
|
38
|
+
const ses = new aws.SES({
|
|
39
|
+
apiVersion: "2010-12-01",
|
|
40
|
+
region,
|
|
41
|
+
credentials: {
|
|
42
|
+
accessKeyId,
|
|
43
|
+
secretAccessKey
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
transporter = nodemailer.createTransport({
|
|
48
|
+
SES: { ses, aws },
|
|
49
|
+
maxConnections: 1,
|
|
50
|
+
sendingRate
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
} else {
|
|
54
|
+
const { user, pass, host, port, secure } = smptConfig;
|
|
55
|
+
transporter = nodemailer.createTransport({
|
|
56
|
+
host,
|
|
57
|
+
port,
|
|
58
|
+
secure,
|
|
59
|
+
auth: { user, pass }
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return transporter;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const send = (transporter: Transporter, email: Email) => {
|
|
67
|
+
return new Promise((resolve, reject) => {
|
|
68
|
+
transporter.once('idle', () => {
|
|
69
|
+
if (transporter.isIdle()) {
|
|
70
|
+
transporter.sendMail(
|
|
71
|
+
email,
|
|
72
|
+
(err, info) => {
|
|
73
|
+
if(err){
|
|
74
|
+
reject(err);
|
|
75
|
+
} else {
|
|
76
|
+
resolve(info);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
};
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { Auth } from './AuthTypes';
|
|
2
|
-
/** For some reason normal import is undefined */
|
|
3
|
-
const passport = require("passport") as typeof import("passport");
|
|
4
|
-
import { Strategy as GoogleStrategy } from "passport-google-oauth20";
|
|
5
|
-
import { Strategy as GitHubStrategy } from "passport-github2";
|
|
6
|
-
import { Strategy as MicrosoftStrategy } from "passport-microsoft";
|
|
7
|
-
import { Strategy as FacebookStrategy } from "passport-facebook";
|
|
8
|
-
import { AuthSocketSchema, getKeys, isDefined, isEmpty } from "prostgles-types";
|
|
9
|
-
import { AUTH_ROUTES_AND_PARAMS, AuthHandler, getLoginClientInfo } from "./AuthHandler";
|
|
10
1
|
import type e from "express";
|
|
11
2
|
import { RequestHandler } from "express";
|
|
12
|
-
import {
|
|
3
|
+
import { Strategy as FacebookStrategy } from "passport-facebook";
|
|
4
|
+
import { Strategy as GitHubStrategy } from "passport-github2";
|
|
5
|
+
import { Strategy as GoogleStrategy } from "passport-google-oauth20";
|
|
6
|
+
import { Strategy as MicrosoftStrategy } from "passport-microsoft";
|
|
7
|
+
import { AuthSocketSchema, getObjectEntries, isEmpty } from "prostgles-types";
|
|
13
8
|
import { getErrorAsObject } from "../DboBuilder/dboBuilderUtils";
|
|
14
|
-
|
|
9
|
+
import { removeExpressRouteByName } from "../FileManager/FileManager";
|
|
10
|
+
import { AUTH_ROUTES_AND_PARAMS, AuthHandler, getLoginClientInfo } from "./AuthHandler";
|
|
11
|
+
import { Auth } from './AuthTypes';
|
|
12
|
+
import { setEmailProvider } from "./setEmailProvider";
|
|
13
|
+
/** For some reason normal import is undefined */
|
|
14
|
+
const passport = require("passport") as typeof import("passport");
|
|
15
15
|
|
|
16
16
|
export const upsertNamedExpressMiddleware = (app: e.Express, handler: RequestHandler, name: string) => {
|
|
17
17
|
const funcName = name;
|
|
@@ -22,56 +22,36 @@ export const upsertNamedExpressMiddleware = (app: e.Express, handler: RequestHan
|
|
|
22
22
|
|
|
23
23
|
export function setAuthProviders (this: AuthHandler, { registrations, app }: Required<Auth>["expressConfig"]) {
|
|
24
24
|
if(!registrations) return;
|
|
25
|
-
const {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const { username, password } = req.body;
|
|
29
|
-
if(typeof username !== "string" || typeof password !== "string"){
|
|
30
|
-
res.status(400).json({ msg: "Invalid username or password" });
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
await onRegister({ provider: "email", profile: { username, password }});
|
|
34
|
-
})
|
|
35
|
-
}
|
|
25
|
+
const { onRegister, onProviderLoginFail, onProviderLoginStart, websiteUrl, OAuthProviders } = registrations;
|
|
26
|
+
|
|
27
|
+
setEmailProvider.bind(this)(app);
|
|
36
28
|
|
|
37
|
-
if(!isEmpty(
|
|
38
|
-
|
|
29
|
+
if(!OAuthProviders || isEmpty(OAuthProviders)){
|
|
30
|
+
return;
|
|
39
31
|
}
|
|
40
32
|
|
|
41
|
-
(
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
providers.github && {
|
|
48
|
-
providerName: "github" as const,
|
|
49
|
-
config: providers.github,
|
|
50
|
-
strategy: GitHubStrategy,
|
|
51
|
-
},
|
|
52
|
-
providers.facebook && {
|
|
53
|
-
providerName: "facebook" as const,
|
|
54
|
-
config: providers.facebook,
|
|
55
|
-
strategy: FacebookStrategy,
|
|
56
|
-
},
|
|
57
|
-
providers.microsoft && {
|
|
58
|
-
providerName: "microsoft" as const,
|
|
59
|
-
config: providers.microsoft,
|
|
60
|
-
strategy: MicrosoftStrategy,
|
|
33
|
+
upsertNamedExpressMiddleware(app, passport.initialize(), "prostglesPassportMiddleware");
|
|
34
|
+
|
|
35
|
+
getObjectEntries(OAuthProviders).forEach(([providerName, providerConfig]) => {
|
|
36
|
+
|
|
37
|
+
if(!providerConfig?.clientID){
|
|
38
|
+
return;
|
|
61
39
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
40
|
+
|
|
41
|
+
const { authOpts, ...config } = providerConfig;
|
|
42
|
+
|
|
43
|
+
const strategy = providerName === "google" ? GoogleStrategy :
|
|
44
|
+
providerName === "github" ? GitHubStrategy :
|
|
45
|
+
providerName === "facebook" ? FacebookStrategy :
|
|
46
|
+
providerName === "microsoft" ? MicrosoftStrategy :
|
|
47
|
+
undefined
|
|
48
|
+
;
|
|
69
49
|
|
|
70
50
|
const callbackPath = `${AUTH_ROUTES_AND_PARAMS.loginWithProvider}/${providerName}/callback`;
|
|
71
51
|
passport.use(
|
|
72
52
|
new (strategy as typeof GoogleStrategy)(
|
|
73
53
|
{
|
|
74
|
-
...config
|
|
54
|
+
...config,
|
|
75
55
|
callbackURL: `${websiteUrl}${callbackPath}`,
|
|
76
56
|
},
|
|
77
57
|
async (accessToken, refreshToken, profile, done) => {
|
|
@@ -92,8 +72,9 @@ export function setAuthProviders (this: AuthHandler, { registrations, app }: Req
|
|
|
92
72
|
try {
|
|
93
73
|
const clientInfo = getLoginClientInfo({ httpReq: req });
|
|
94
74
|
const db = this.db;
|
|
95
|
-
const dbo = this.dbo as any
|
|
96
|
-
const
|
|
75
|
+
const dbo = this.dbo as any;
|
|
76
|
+
const args = { provider: providerName, req, res, clientInfo, db, dbo };
|
|
77
|
+
const startCheck = await onProviderLoginStart(args);
|
|
97
78
|
if("error" in startCheck){
|
|
98
79
|
res.status(500).json({ error: startCheck.error });
|
|
99
80
|
return;
|
|
@@ -107,7 +88,7 @@ export function setAuthProviders (this: AuthHandler, { registrations, app }: Req
|
|
|
107
88
|
},
|
|
108
89
|
async (error: any, _profile: any, authInfo: any) => {
|
|
109
90
|
if(error){
|
|
110
|
-
await onProviderLoginFail({
|
|
91
|
+
await onProviderLoginFail({ ...args, error });
|
|
111
92
|
res.status(500).json({
|
|
112
93
|
error: "Failed to login with provider",
|
|
113
94
|
});
|
|
@@ -120,7 +101,7 @@ export function setAuthProviders (this: AuthHandler, { registrations, app }: Req
|
|
|
120
101
|
}
|
|
121
102
|
)(req, res);
|
|
122
103
|
|
|
123
|
-
} catch (
|
|
104
|
+
} catch (_e) {
|
|
124
105
|
res.status(500).json({ error: "Something went wrong" });
|
|
125
106
|
}
|
|
126
107
|
}
|
|
@@ -132,16 +113,12 @@ export function setAuthProviders (this: AuthHandler, { registrations, app }: Req
|
|
|
132
113
|
export function getProviders(this: AuthHandler): AuthSocketSchema["providers"] | undefined {
|
|
133
114
|
const { registrations } = this.opts?.expressConfig ?? {}
|
|
134
115
|
if(!registrations) return undefined;
|
|
135
|
-
const {
|
|
136
|
-
|
|
137
|
-
email, websiteUrl, onRegister, onProviderLoginFail, onProviderLoginStart,
|
|
138
|
-
...providers
|
|
139
|
-
} = registrations;
|
|
140
|
-
if(isEmpty(providers)) return undefined;
|
|
116
|
+
const { OAuthProviders } = registrations;
|
|
117
|
+
if(!OAuthProviders || isEmpty(OAuthProviders)) return undefined;
|
|
141
118
|
|
|
142
119
|
const result: AuthSocketSchema["providers"] = {}
|
|
143
|
-
|
|
144
|
-
if(
|
|
120
|
+
getObjectEntries(OAuthProviders).forEach(([providerName, config]) => {
|
|
121
|
+
if(config?.clientID){
|
|
145
122
|
result[providerName] = {
|
|
146
123
|
url: `${AUTH_ROUTES_AND_PARAMS.loginWithProvider}/${providerName}`,
|
|
147
124
|
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import e from "express";
|
|
2
|
+
import { AUTH_ROUTES_AND_PARAMS, AuthHandler } from "./AuthHandler";
|
|
3
|
+
import { Email, SMTPConfig } from "./AuthTypes";
|
|
4
|
+
import { sendEmail } from "./sendEmail";
|
|
5
|
+
|
|
6
|
+
export function setEmailProvider(this: AuthHandler, app: e.Express) {
|
|
7
|
+
|
|
8
|
+
const { email, websiteUrl } = this.opts?.expressConfig?.registrations ?? {};
|
|
9
|
+
if(!email) return;
|
|
10
|
+
|
|
11
|
+
app.post(AUTH_ROUTES_AND_PARAMS.emailSignup, async (req, res) => {
|
|
12
|
+
const { username, password } = req.body;
|
|
13
|
+
let validationError = "";
|
|
14
|
+
if(typeof username !== "string"){
|
|
15
|
+
validationError = "Invalid username";
|
|
16
|
+
}
|
|
17
|
+
if(email.signupType === "withPassword"){
|
|
18
|
+
const { minPasswordLength = 8 } = email;
|
|
19
|
+
if(typeof password !== "string"){
|
|
20
|
+
validationError = "Invalid password";
|
|
21
|
+
} else if(password.length < minPasswordLength){
|
|
22
|
+
validationError = `Password must be at least ${minPasswordLength} characters long`;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if(validationError){
|
|
26
|
+
res.status(400).json({ error: validationError });
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
let emailMessage: undefined | { message: Email; smtp: SMTPConfig };
|
|
31
|
+
if(email.signupType === "withPassword"){
|
|
32
|
+
if(email.emailConfirmation){
|
|
33
|
+
const { onSend, smtp } = email.emailConfirmation;
|
|
34
|
+
const message = await onSend({ email: username, confirmationUrlPath: `${websiteUrl}${AUTH_ROUTES_AND_PARAMS.confirmEmail}` });
|
|
35
|
+
emailMessage = { message: { ...message, to: username }, smtp };
|
|
36
|
+
}
|
|
37
|
+
} else {
|
|
38
|
+
const { emailMagicLink } = email;
|
|
39
|
+
const message = await emailMagicLink.onSend({ email: username, magicLinkPath: `${websiteUrl}${AUTH_ROUTES_AND_PARAMS.magicLinksRoute}` });
|
|
40
|
+
emailMessage = { message: { ...message, to: username }, smtp: emailMagicLink.smtp };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if(emailMessage){
|
|
44
|
+
await sendEmail(emailMessage.smtp, emailMessage.message);
|
|
45
|
+
res.json({ msg: "Email sent" });
|
|
46
|
+
}
|
|
47
|
+
} catch {
|
|
48
|
+
res.status(500).json({ error: "Failed to send email" });
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
if(email.signupType === "withPassword" && email.emailConfirmation){
|
|
53
|
+
app.get(AUTH_ROUTES_AND_PARAMS.confirmEmailExpressRoute, async (req, res) => {
|
|
54
|
+
const { id } = req.params ?? {};
|
|
55
|
+
try {
|
|
56
|
+
await email.emailConfirmation?.onConfirmed({ confirmationUrlPath: id });
|
|
57
|
+
res.json({ msg: "Email confirmed" });
|
|
58
|
+
} catch (_e) {
|
|
59
|
+
res.status(500).json({ error: "Failed to confirm email" });
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prostgles-server",
|
|
3
|
-
"version": "4.2.
|
|
3
|
+
"version": "4.2.157",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -35,9 +35,17 @@
|
|
|
35
35
|
],
|
|
36
36
|
"homepage": "https://prostgles.com",
|
|
37
37
|
"dependencies": {
|
|
38
|
+
"@aws-sdk/client-ses": "^3.699.0",
|
|
39
|
+
"@aws-sdk/credential-provider-node": "^3.699.0",
|
|
40
|
+
"@types/passport": "^1.0.17",
|
|
41
|
+
"@types/passport-facebook": "^3.0.3",
|
|
42
|
+
"@types/passport-github2": "^1.2.9",
|
|
43
|
+
"@types/passport-google-oauth20": "^2.0.16",
|
|
44
|
+
"@types/passport-microsoft": "^1.0.3",
|
|
38
45
|
"body-parser": "^1.20.3",
|
|
39
46
|
"check-disk-space": "^3.4.0",
|
|
40
47
|
"file-type": "^18.5.0",
|
|
48
|
+
"nodemailer": "^6.9.16",
|
|
41
49
|
"passport": "^0.7.0",
|
|
42
50
|
"passport-facebook": "^3.0.0",
|
|
43
51
|
"passport-github2": "^0.1.12",
|
|
@@ -46,17 +54,13 @@
|
|
|
46
54
|
"pg": "^8.11.5",
|
|
47
55
|
"pg-cursor": "^2.11.0",
|
|
48
56
|
"pg-promise": "^11.9.1",
|
|
49
|
-
"prostgles-types": "^4.0.
|
|
57
|
+
"prostgles-types": "^4.0.107"
|
|
50
58
|
},
|
|
51
59
|
"devDependencies": {
|
|
52
60
|
"@types/express": "^4.17.21",
|
|
53
61
|
"@types/json-schema": "^7.0.15",
|
|
54
62
|
"@types/node": "^22.8.1",
|
|
55
|
-
"@types/
|
|
56
|
-
"@types/passport-facebook": "^3.0.3",
|
|
57
|
-
"@types/passport-github2": "^1.2.9",
|
|
58
|
-
"@types/passport-google-oauth20": "^2.0.16",
|
|
59
|
-
"@types/passport-microsoft": "^1.0.3",
|
|
63
|
+
"@types/nodemailer": "^6.4.17",
|
|
60
64
|
"@types/pg": "^8.11.5",
|
|
61
65
|
"@types/pg-cursor": "^2.7.2",
|
|
62
66
|
"@types/sharp": "^0.30.4",
|