@canmingir/link-express 1.6.11 → 1.7.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/.eslintrc.ts +29 -0
- package/index.ts +2 -0
- package/package.json +52 -12
- package/{prepare.js → prepare.ts} +1 -1
- package/src/{authorization.js → authorization.ts} +31 -9
- package/src/config.ts +112 -0
- package/src/dynamodb.ts +24 -0
- package/src/{error.js → error.ts} +30 -11
- package/src/express.ts +66 -0
- package/src/lib/{settings.js → settings.ts} +16 -4
- package/src/lib/test.ts +68 -0
- package/src/{logger.js → logger.ts} +11 -9
- package/src/metrics/{dbMetrics.js → dbMetrics.ts} +37 -14
- package/src/models/Organization.model.ts +27 -0
- package/src/models/Permission.model.ts +48 -0
- package/src/models/Project.model.ts +50 -0
- package/src/models/Settings.model.ts +31 -0
- package/src/models/{index.js → index.ts} +8 -8
- package/src/platform.ts +55 -0
- package/src/postgres.ts +309 -0
- package/src/routes/index.ts +8 -0
- package/src/routes/metrics.ts +13 -0
- package/src/routes/oauth.ts +267 -0
- package/src/routes/{organizations.js → organizations.ts} +10 -8
- package/src/routes/{permissions.js → permissions.ts} +8 -6
- package/src/routes/{projects.js → projects.ts} +22 -16
- package/src/routes/settings.ts +31 -0
- package/src/schemas/{Organization.js → Organization.ts} +2 -2
- package/src/schemas/{Permission.js → Permission.ts} +2 -2
- package/src/schemas/{Project.js → Project.ts} +2 -2
- package/src/schemas/index.ts +5 -0
- package/src/sequelize.ts +13 -0
- package/src/{test.js → test.ts} +11 -13
- package/src/types/Organization.ts +9 -0
- package/src/types/Permission.ts +13 -0
- package/src/types/Project.ts +14 -0
- package/src/types/index.ts +5 -0
- package/tsconfig.json +32 -0
- package/.eslintrc.js +0 -20
- package/index.js +0 -1
- package/src/config.js +0 -21
- package/src/dynamodb.js +0 -18
- package/src/express.js +0 -58
- package/src/lib/test.js +0 -69
- package/src/models/Organization.js +0 -17
- package/src/models/Permission.js +0 -33
- package/src/models/Project.js +0 -37
- package/src/models/Settings.js +0 -21
- package/src/openapi.js +0 -40
- package/src/platform.js +0 -56
- package/src/postgres.js +0 -308
- package/src/routes/index.js +0 -15
- package/src/routes/metrics.js +0 -12
- package/src/routes/oauth.js +0 -213
- package/src/routes/settings.js +0 -25
- package/src/schemas/index.js +0 -5
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import Joi from "joi";
|
|
2
|
+
import express, { Request, Response } from "express";
|
|
3
|
+
import jwt from "jsonwebtoken";
|
|
4
|
+
import axios from "axios";
|
|
5
|
+
import config from "../config";
|
|
6
|
+
import { AuthenticationError, AuthorizationError } from "../error";
|
|
7
|
+
import Permission from "../models/Permission.model";
|
|
8
|
+
|
|
9
|
+
const router = express.Router();
|
|
10
|
+
|
|
11
|
+
const { project } = config();
|
|
12
|
+
|
|
13
|
+
if (!project) {
|
|
14
|
+
throw new Error("Project configuration is required");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
router.post(
|
|
18
|
+
"/",
|
|
19
|
+
async (req: Request, res: Response): Promise<Response | void> => {
|
|
20
|
+
const { appId, projectId, code, refreshToken, redirectUri, provider } =
|
|
21
|
+
Joi.attempt(
|
|
22
|
+
req.body,
|
|
23
|
+
Joi.object({
|
|
24
|
+
appId: Joi.string().required(),
|
|
25
|
+
projectId: Joi.string().optional(),
|
|
26
|
+
code: Joi.string().optional(),
|
|
27
|
+
refreshToken: Joi.string().optional(),
|
|
28
|
+
redirectUri: Joi.string().optional(),
|
|
29
|
+
provider: Joi.string().required(),
|
|
30
|
+
})
|
|
31
|
+
.required()
|
|
32
|
+
.options({ stripUnknown: true })
|
|
33
|
+
) as {
|
|
34
|
+
appId: string;
|
|
35
|
+
projectId?: string;
|
|
36
|
+
code?: string;
|
|
37
|
+
refreshToken?: string;
|
|
38
|
+
redirectUri?: string;
|
|
39
|
+
provider: string;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
if (!code && !refreshToken) {
|
|
43
|
+
return res.status(400).send("Missing OAuth Code and Refresh Token");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const providerConfig = project.oauth?.providers[provider] as {
|
|
47
|
+
clientId: string;
|
|
48
|
+
tokenUrl: string;
|
|
49
|
+
userUrl: string;
|
|
50
|
+
userIdentifier: string;
|
|
51
|
+
userFields: {
|
|
52
|
+
name: string;
|
|
53
|
+
displayName: string;
|
|
54
|
+
avatarUrl: string;
|
|
55
|
+
email: string;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
if (!providerConfig) {
|
|
59
|
+
return res.status(400).send("Unsupported OAuth provider");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
let accessTokenForAPI: string;
|
|
63
|
+
let newRefreshToken = refreshToken;
|
|
64
|
+
|
|
65
|
+
if (code && redirectUri) {
|
|
66
|
+
const params = new URLSearchParams();
|
|
67
|
+
params.append("grant_type", "authorization_code");
|
|
68
|
+
params.append("client_id", providerConfig.clientId);
|
|
69
|
+
params.append(
|
|
70
|
+
"client_secret",
|
|
71
|
+
process.env[`${provider.toUpperCase()}_CLIENT_SECRET`] as string
|
|
72
|
+
);
|
|
73
|
+
params.append("code", code);
|
|
74
|
+
params.append("redirect_uri", redirectUri);
|
|
75
|
+
|
|
76
|
+
const tokenResponse = await axios.post<{
|
|
77
|
+
access_token?: string;
|
|
78
|
+
refresh_token?: string;
|
|
79
|
+
error?: string;
|
|
80
|
+
error_description?: string;
|
|
81
|
+
}>(providerConfig.tokenUrl, params.toString(), {
|
|
82
|
+
headers: {
|
|
83
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
84
|
+
Accept: "application/json",
|
|
85
|
+
},
|
|
86
|
+
timeout: 10000,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
if (tokenResponse.data.error) {
|
|
90
|
+
throw new AuthorizationError(
|
|
91
|
+
tokenResponse.data.error_description || tokenResponse.data.error
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (!tokenResponse.data.access_token) {
|
|
96
|
+
throw new AuthenticationError(
|
|
97
|
+
"No access token received from OAuth provider"
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
accessTokenForAPI = tokenResponse.data.access_token;
|
|
102
|
+
newRefreshToken =
|
|
103
|
+
tokenResponse.data.refresh_token || tokenResponse.data.access_token;
|
|
104
|
+
} else {
|
|
105
|
+
accessTokenForAPI = refreshToken as string;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const userResponse = await axios.get<Record<string, unknown>>(
|
|
109
|
+
providerConfig.userUrl,
|
|
110
|
+
{
|
|
111
|
+
headers: {
|
|
112
|
+
Authorization: `Bearer ${accessTokenForAPI}`,
|
|
113
|
+
Accept: "application/json",
|
|
114
|
+
},
|
|
115
|
+
timeout: 10000,
|
|
116
|
+
}
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
console.log("User info response:", userResponse.data);
|
|
120
|
+
|
|
121
|
+
let userId: string;
|
|
122
|
+
const identifierField = providerConfig.userIdentifier;
|
|
123
|
+
|
|
124
|
+
if (userResponse.data[identifierField]) {
|
|
125
|
+
userId = String(userResponse.data[identifierField]);
|
|
126
|
+
} else if (
|
|
127
|
+
project.oauth &&
|
|
128
|
+
project.oauth?.jwt.identifier &&
|
|
129
|
+
userResponse.data[project.oauth.jwt.identifier]
|
|
130
|
+
) {
|
|
131
|
+
userId = String(userResponse.data[project.oauth.jwt.identifier]);
|
|
132
|
+
} else {
|
|
133
|
+
console.error("User identifier extraction failed:", {
|
|
134
|
+
availableFields: Object.keys(userResponse.data),
|
|
135
|
+
expectedField: identifierField,
|
|
136
|
+
fallbackField: project.oauth?.jwt.identifier,
|
|
137
|
+
});
|
|
138
|
+
throw new Error(
|
|
139
|
+
`Cannot find user identifier in ${provider} OAuth response`
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
let accessToken: string;
|
|
144
|
+
|
|
145
|
+
if (projectId) {
|
|
146
|
+
const permissions = await Permission.findAll({
|
|
147
|
+
where: { userId, projectId, appId },
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
if (!permissions.length) {
|
|
151
|
+
accessToken = jwt.sign(
|
|
152
|
+
{
|
|
153
|
+
sub: userId,
|
|
154
|
+
iss: "nuc",
|
|
155
|
+
aid: appId,
|
|
156
|
+
provider: provider,
|
|
157
|
+
iat: Math.floor(Date.now() / 1000),
|
|
158
|
+
},
|
|
159
|
+
process.env.JWT_SECRET as string,
|
|
160
|
+
{ expiresIn: "12h" }
|
|
161
|
+
);
|
|
162
|
+
} else {
|
|
163
|
+
accessToken = jwt.sign(
|
|
164
|
+
{
|
|
165
|
+
sub: userId,
|
|
166
|
+
iss: "nuc",
|
|
167
|
+
aud: projectId,
|
|
168
|
+
oid: permissions[0].organizationId,
|
|
169
|
+
aid: appId,
|
|
170
|
+
rls: permissions.map((permission) => permission.role),
|
|
171
|
+
provider: provider,
|
|
172
|
+
iat: Math.floor(Date.now() / 1000),
|
|
173
|
+
},
|
|
174
|
+
process.env.JWT_SECRET as string,
|
|
175
|
+
{ expiresIn: "12h" }
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
} else {
|
|
179
|
+
accessToken = jwt.sign(
|
|
180
|
+
{
|
|
181
|
+
sub: userId,
|
|
182
|
+
iss: "nuc",
|
|
183
|
+
aid: appId,
|
|
184
|
+
provider: provider,
|
|
185
|
+
iat: Math.floor(Date.now() / 1000),
|
|
186
|
+
},
|
|
187
|
+
process.env.JWT_SECRET as string,
|
|
188
|
+
{ expiresIn: "12h" }
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
res.status(200).json({
|
|
193
|
+
accessToken,
|
|
194
|
+
refreshToken: newRefreshToken,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
router.get("/user", async (req: Request, res: Response): Promise<Response> => {
|
|
200
|
+
const authHeader = req.headers.authorization;
|
|
201
|
+
const refreshTokenHeader = req.headers["x-refresh-token"] as
|
|
202
|
+
| string
|
|
203
|
+
| undefined;
|
|
204
|
+
|
|
205
|
+
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
206
|
+
return res.status(401).end();
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (!refreshTokenHeader) {
|
|
210
|
+
return res.status(400).send("Missing refresh token");
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const token = authHeader.split(" ")[1];
|
|
214
|
+
|
|
215
|
+
const decoded = jwt.verify(token, process.env.JWT_SECRET as string) as {
|
|
216
|
+
sub: string;
|
|
217
|
+
provider: string;
|
|
218
|
+
};
|
|
219
|
+
const userId = decoded.sub;
|
|
220
|
+
const provider = decoded.provider;
|
|
221
|
+
|
|
222
|
+
if (!userId || !provider) {
|
|
223
|
+
return res.status(401).end();
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const providerConfig = project.oauth?.providers[provider] as {
|
|
227
|
+
userUrl: string;
|
|
228
|
+
userFields: {
|
|
229
|
+
name: string;
|
|
230
|
+
displayName: string;
|
|
231
|
+
avatarUrl: string;
|
|
232
|
+
email: string;
|
|
233
|
+
};
|
|
234
|
+
};
|
|
235
|
+
if (!providerConfig) {
|
|
236
|
+
return res.status(400).send("Unsupported OAuth provider");
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const userResponse = await axios.get<Record<string, unknown>>(
|
|
240
|
+
providerConfig.userUrl,
|
|
241
|
+
{
|
|
242
|
+
headers: {
|
|
243
|
+
Authorization: `Bearer ${refreshTokenHeader}`,
|
|
244
|
+
Accept: "application/json",
|
|
245
|
+
},
|
|
246
|
+
timeout: 10000,
|
|
247
|
+
}
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
const userFieldMapping = providerConfig.userFields;
|
|
251
|
+
const userDetails = {
|
|
252
|
+
id: userId,
|
|
253
|
+
provider: provider,
|
|
254
|
+
name: (userResponse.data[userFieldMapping.name] as string) || null,
|
|
255
|
+
displayName:
|
|
256
|
+
(userResponse.data[userFieldMapping.displayName] as string) || null,
|
|
257
|
+
avatarUrl:
|
|
258
|
+
(userResponse.data[userFieldMapping.avatarUrl] as string) || null,
|
|
259
|
+
email: (userResponse.data[userFieldMapping.email] as string) || null,
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
return res.status(200).json({
|
|
263
|
+
user: userDetails,
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
export default router;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import express, { Request, Response } from "express";
|
|
2
|
+
import Organization from "../models/Organization.model";
|
|
3
|
+
import Permission from "../models/Permission.model";
|
|
4
4
|
|
|
5
|
-
router
|
|
5
|
+
const router = express.Router();
|
|
6
|
+
|
|
7
|
+
router.post("/", async (req: Request, res: Response) => {
|
|
6
8
|
const organization = req.body;
|
|
7
9
|
|
|
8
10
|
Organization.create(organization).then((organization) => {
|
|
@@ -10,7 +12,7 @@ router.post("/", async (req, res) => {
|
|
|
10
12
|
});
|
|
11
13
|
});
|
|
12
14
|
|
|
13
|
-
router.get("/", async (req, res) => {
|
|
15
|
+
router.get("/", async (req: Request, res: Response) => {
|
|
14
16
|
const { userId } = req.session;
|
|
15
17
|
|
|
16
18
|
const organizations = await Organization.findAll({
|
|
@@ -27,7 +29,7 @@ router.get("/", async (req, res) => {
|
|
|
27
29
|
res.status(200).json(organizations);
|
|
28
30
|
});
|
|
29
31
|
|
|
30
|
-
router.get("/:id", async (req, res) => {
|
|
32
|
+
router.get("/:id", async (req: Request, res: Response) => {
|
|
31
33
|
const { organizationId } = req.session;
|
|
32
34
|
const { id } = req.params;
|
|
33
35
|
|
|
@@ -36,7 +38,7 @@ router.get("/:id", async (req, res) => {
|
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
const organization = await Organization.findByPk(organizationId);
|
|
39
|
-
res.status(200).json(organization);
|
|
41
|
+
return res.status(200).json(organization);
|
|
40
42
|
});
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
export default router;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import express, { Request, Response } from "express";
|
|
2
|
+
import Permission from "../models/Permission.model";
|
|
3
3
|
|
|
4
|
-
router
|
|
4
|
+
const router = express.Router();
|
|
5
|
+
|
|
6
|
+
router.post("/", async (req: Request, res: Response) => {
|
|
5
7
|
const { userId } = req.body;
|
|
6
8
|
const { projectId, organizationId, appId, roles } = req.session;
|
|
7
9
|
const permissionInstance = await Permission.create({
|
|
@@ -14,7 +16,7 @@ router.post("/", async (req, res) => {
|
|
|
14
16
|
res.status(201).json(permissionInstance);
|
|
15
17
|
});
|
|
16
18
|
|
|
17
|
-
router.get("/", async (req, res) => {
|
|
19
|
+
router.get("/", async (req: Request, res: Response) => {
|
|
18
20
|
const { projectId, organizationId } = req.session;
|
|
19
21
|
|
|
20
22
|
const permissions = await Permission.findAll({
|
|
@@ -31,7 +33,7 @@ router.get("/", async (req, res) => {
|
|
|
31
33
|
}
|
|
32
34
|
});
|
|
33
35
|
|
|
34
|
-
router.delete("/:userId", async (req, res) => {
|
|
36
|
+
router.delete("/:userId", async (req: Request, res: Response) => {
|
|
35
37
|
const { projectId, organizationId } = req.session;
|
|
36
38
|
const userId = req.params.userId;
|
|
37
39
|
|
|
@@ -47,4 +49,4 @@ router.delete("/:userId", async (req, res) => {
|
|
|
47
49
|
}
|
|
48
50
|
});
|
|
49
51
|
|
|
50
|
-
|
|
52
|
+
export default router;
|
|
@@ -1,16 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
router
|
|
1
|
+
import Joi from "joi";
|
|
2
|
+
import express, { Request, Response } from "express";
|
|
3
|
+
import Project from "../models/Project.model";
|
|
4
|
+
import Organization from "../models/Organization.model";
|
|
5
|
+
import Permission from "../models/Permission.model";
|
|
6
|
+
import * as schemas from "../schemas";
|
|
7
|
+
import config from "../config";
|
|
8
|
+
|
|
9
|
+
const router = express.Router();
|
|
10
|
+
|
|
11
|
+
router.post("/", async (req: Request, res: Response) => {
|
|
10
12
|
const project = Joi.attempt(req.body, schemas.Project);
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
const appConfig = config();
|
|
15
|
+
if (appConfig.link && appConfig.link.project) {
|
|
16
|
+
Joi.attempt(
|
|
17
|
+
project.type,
|
|
18
|
+
(appConfig.link.project as { type: Joi.Schema }).type
|
|
19
|
+
);
|
|
14
20
|
}
|
|
15
21
|
|
|
16
22
|
const projectInstance = await Project.create(project);
|
|
@@ -26,7 +32,7 @@ router.post("/", async (req, res) => {
|
|
|
26
32
|
res.status(201).json(projectInstance);
|
|
27
33
|
});
|
|
28
34
|
|
|
29
|
-
router.get("/", async (req, res) => {
|
|
35
|
+
router.get("/", async (req: Request, res: Response) => {
|
|
30
36
|
const { userId, appId } = req.session;
|
|
31
37
|
|
|
32
38
|
const projects = await Project.findAll({
|
|
@@ -50,7 +56,7 @@ router.get("/", async (req, res) => {
|
|
|
50
56
|
res.status(200).json(projects);
|
|
51
57
|
});
|
|
52
58
|
|
|
53
|
-
router.get("/:id", async (req, res) => {
|
|
59
|
+
router.get("/:id", async (req: Request, res: Response) => {
|
|
54
60
|
const { userId, organizationId } = req.session;
|
|
55
61
|
const { id } = req.params;
|
|
56
62
|
|
|
@@ -73,7 +79,7 @@ router.get("/:id", async (req, res) => {
|
|
|
73
79
|
}
|
|
74
80
|
});
|
|
75
81
|
|
|
76
|
-
router.delete("/:id", async (req, res) => {
|
|
82
|
+
router.delete("/:id", async (req: Request, res: Response) => {
|
|
77
83
|
const { userId, organizationId } = req.session;
|
|
78
84
|
const { id } = req.params;
|
|
79
85
|
|
|
@@ -97,7 +103,7 @@ router.delete("/:id", async (req, res) => {
|
|
|
97
103
|
}
|
|
98
104
|
});
|
|
99
105
|
|
|
100
|
-
router.patch("/:id", async (req, res) => {
|
|
106
|
+
router.patch("/:id", async (req: Request, res: Response) => {
|
|
101
107
|
const { userId, organizationId } = req.session;
|
|
102
108
|
const { id } = req.params;
|
|
103
109
|
|
|
@@ -122,4 +128,4 @@ router.patch("/:id", async (req, res) => {
|
|
|
122
128
|
}
|
|
123
129
|
});
|
|
124
130
|
|
|
125
|
-
|
|
131
|
+
export default router;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import express, { Request, Response } from "express";
|
|
2
|
+
import * as settings from "../lib/settings";
|
|
3
|
+
import { AuthorizationError } from "../error";
|
|
4
|
+
|
|
5
|
+
const router = express.Router({ mergeParams: true });
|
|
6
|
+
|
|
7
|
+
interface SettingsRequest extends Request {
|
|
8
|
+
params: {
|
|
9
|
+
projectId: string;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
router.get("/", async (req: SettingsRequest, res: Response) => {
|
|
14
|
+
if (req.params.projectId !== req.session.projectId) {
|
|
15
|
+
throw new AuthorizationError();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const setting = await settings.get(req.session);
|
|
19
|
+
res.json(setting);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
router.patch("/", async (req: SettingsRequest, res: Response) => {
|
|
23
|
+
if (req.params.projectId !== req.session.projectId) {
|
|
24
|
+
throw new AuthorizationError();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
await settings.upsert(req.session, req.body, req.params);
|
|
28
|
+
res.end();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export default router;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import Joi from "joi";
|
|
2
2
|
|
|
3
3
|
const Project = Joi.object({
|
|
4
4
|
name: Joi.string().required(),
|
|
@@ -11,4 +11,4 @@ const Project = Joi.object({
|
|
|
11
11
|
coach: Joi.string().optional(),
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
export = Project;
|
package/src/sequelize.ts
ADDED
package/src/{test.js → test.ts}
RENAMED
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import dotenv from "dotenv";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
import platform from "./platform";
|
|
5
|
+
|
|
6
|
+
dotenv.config({ path: ".env.test" });
|
|
5
7
|
|
|
6
8
|
platform
|
|
7
9
|
.init({
|
|
8
10
|
postgres: { uri: "sqlite::memory:", debug: true },
|
|
9
11
|
dynamodb: {
|
|
10
12
|
region: "us-test-1",
|
|
11
|
-
credentials: {
|
|
12
|
-
accessKeyId: "test",
|
|
13
|
-
secretAccessKey: "test",
|
|
14
|
-
},
|
|
15
13
|
},
|
|
16
14
|
})
|
|
17
15
|
.then(async () => {
|
|
@@ -28,11 +26,11 @@ const seedsDir = path.join(workingDir, "src", "seeds");
|
|
|
28
26
|
|
|
29
27
|
const models = require(modelsDir);
|
|
30
28
|
|
|
31
|
-
function project(id) {
|
|
29
|
+
function project(id: string): void {
|
|
32
30
|
process.env.PROJECT_ID = id;
|
|
33
31
|
}
|
|
34
32
|
|
|
35
|
-
async function reset() {
|
|
33
|
+
async function reset(): Promise<void> {
|
|
36
34
|
const {
|
|
37
35
|
Postgres: { sequelize },
|
|
38
36
|
} = platform.module();
|
|
@@ -57,7 +55,7 @@ async function reset() {
|
|
|
57
55
|
}
|
|
58
56
|
});
|
|
59
57
|
|
|
60
|
-
async function seed() {
|
|
58
|
+
async function seed(): Promise<void> {
|
|
61
59
|
const { seed: organizations } = require("./seeds/Organization.json");
|
|
62
60
|
const { seed: projects } = require("./seeds/Project.json");
|
|
63
61
|
const { seed: permissions } = require("./seeds/Permission.json");
|
|
@@ -78,7 +76,7 @@ async function reset() {
|
|
|
78
76
|
await Project.bulkCreate(allProjects);
|
|
79
77
|
|
|
80
78
|
const seedFileNames = fs.readdirSync(seedsDir);
|
|
81
|
-
let orderedSeeds = [];
|
|
79
|
+
let orderedSeeds: { sequence: number; seed: unknown[]; modelName: string }[] = [];
|
|
82
80
|
|
|
83
81
|
seedFileNames.forEach(async (seedFileName) => {
|
|
84
82
|
if (seedFileName === "index.js") return;
|
|
@@ -102,4 +100,4 @@ async function reset() {
|
|
|
102
100
|
await seed();
|
|
103
101
|
}
|
|
104
102
|
|
|
105
|
-
|
|
103
|
+
export { reset, project };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { OrganizationType } from "./Organization";
|
|
2
|
+
import type { ProjectType } from "./Project";
|
|
3
|
+
|
|
4
|
+
export interface PermissionType {
|
|
5
|
+
id: string;
|
|
6
|
+
appId: string;
|
|
7
|
+
organizationId: string;
|
|
8
|
+
projectId: string;
|
|
9
|
+
userId: string;
|
|
10
|
+
role: string;
|
|
11
|
+
organization?: OrganizationType;
|
|
12
|
+
project?: ProjectType;
|
|
13
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { OrganizationType } from "./Organization";
|
|
2
|
+
import type { PermissionType } from "./Permission";
|
|
3
|
+
|
|
4
|
+
export interface ProjectType {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
icon: string;
|
|
8
|
+
description: string | null;
|
|
9
|
+
type: string | null;
|
|
10
|
+
organizationId: string | null;
|
|
11
|
+
coach: string | null;
|
|
12
|
+
organization?: OrganizationType;
|
|
13
|
+
permissions?: PermissionType[];
|
|
14
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"lib": ["ES2020"],
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"rootDir": "./",
|
|
9
|
+
"removeComments": true,
|
|
10
|
+
"strict": true,
|
|
11
|
+
"noImplicitAny": true,
|
|
12
|
+
"strictNullChecks": true,
|
|
13
|
+
"strictFunctionTypes": true,
|
|
14
|
+
"strictBindCallApply": true,
|
|
15
|
+
"strictPropertyInitialization": false,
|
|
16
|
+
"noImplicitThis": true,
|
|
17
|
+
"alwaysStrict": true,
|
|
18
|
+
"noUnusedLocals": true,
|
|
19
|
+
"noUnusedParameters": true,
|
|
20
|
+
"noImplicitReturns": true,
|
|
21
|
+
"noFallthroughCasesInSwitch": true,
|
|
22
|
+
"esModuleInterop": true,
|
|
23
|
+
"skipLibCheck": true,
|
|
24
|
+
"forceConsistentCasingInFileNames": true,
|
|
25
|
+
"moduleResolution": "node",
|
|
26
|
+
"resolveJsonModule": true,
|
|
27
|
+
"experimentalDecorators": true,
|
|
28
|
+
"emitDecoratorMetadata": true
|
|
29
|
+
},
|
|
30
|
+
"include": ["src/**/*", "index.ts", "prepare.ts"],
|
|
31
|
+
"exclude": ["node_modules", "dist", "**/*.spec.ts", "**/*.test.ts"]
|
|
32
|
+
}
|
package/.eslintrc.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
env: {
|
|
3
|
-
es6: true,
|
|
4
|
-
node: true,
|
|
5
|
-
mocha: true,
|
|
6
|
-
},
|
|
7
|
-
extends: ["eslint:recommended", "plugin:prettier/recommended"],
|
|
8
|
-
parserOptions: {
|
|
9
|
-
ecmaVersion: 2022,
|
|
10
|
-
sourceType: "module",
|
|
11
|
-
},
|
|
12
|
-
ignorePatterns: "/node_modules",
|
|
13
|
-
rules: {
|
|
14
|
-
eqeqeq: ["error", "always"],
|
|
15
|
-
"no-console": "off",
|
|
16
|
-
"no-eval": "error",
|
|
17
|
-
"no-var": "error",
|
|
18
|
-
"prefer-arrow-callback": "error",
|
|
19
|
-
},
|
|
20
|
-
};
|
package/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
module.exports = require("./src/platform");
|