@canmingir/link-express 1.6.1 → 1.6.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canmingir/link-express",
3
- "version": "1.6.1",
3
+ "version": "1.6.2",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "author": "NucTeam",
package/src/lib/test.js CHANGED
@@ -7,10 +7,21 @@ init({
7
7
  jwt: {
8
8
  identifier: "email",
9
9
  },
10
- tokenUrl: "https://github.com/login/oauth/access_token",
11
- userUrl: "https://api.github.com/user",
12
- clientId: "0c2844d3d19dc9293fc5",
13
- redirectUri: "http://localhost:5173/callback",
10
+ providers: {
11
+ github: {
12
+ tokenUrl: "https://github.com/login/oauth/access_token",
13
+ userUrl: "https://api.github.com/user",
14
+ clientId: "0c2844d3d19dc9293fc5",
15
+ redirectUri: "http://localhost:5173/callback",
16
+ userIdentifier: "id",
17
+ userFields: {
18
+ name: "name",
19
+ displayName: "login",
20
+ avatarUrl: "avatar_url",
21
+ email: "email",
22
+ },
23
+ },
24
+ },
14
25
  },
15
26
  },
16
27
  postgres: {
@@ -3,24 +3,25 @@ const router = require("express").Router();
3
3
  const jwt = require("jsonwebtoken");
4
4
  const axios = require("axios");
5
5
  const config = require("../config");
6
- const { AuthenticationError } = require("../error");
6
+ const { AuthenticationError, AuthorizationError } = require("../error");
7
7
  const Permission = require("../models/Permission");
8
8
  const { project } = config();
9
9
 
10
10
  router.post("/", async (req, res) => {
11
- let { appId, projectId, code, refreshToken, redirectUri, provider } = Joi.attempt(
12
- req.body,
13
- Joi.object({
14
- appId: Joi.string().required(),
15
- projectId: Joi.string().optional(),
16
- code: Joi.string().optional(),
17
- refreshToken: Joi.string().optional(),
18
- redirectUri: Joi.string().optional(),
19
- provider: Joi.string().required(),
20
- })
21
- .required()
22
- .options({ stripUnknown: true })
23
- );
11
+ let { appId, projectId, code, refreshToken, redirectUri, provider } =
12
+ Joi.attempt(
13
+ req.body,
14
+ Joi.object({
15
+ appId: Joi.string().required(),
16
+ projectId: Joi.string().optional(),
17
+ code: Joi.string().optional(),
18
+ refreshToken: Joi.string().optional(),
19
+ redirectUri: Joi.string().optional(),
20
+ provider: Joi.string().required(),
21
+ })
22
+ .required()
23
+ .options({ stripUnknown: true })
24
+ );
24
25
 
25
26
  if (!code && !refreshToken) {
26
27
  return res.status(400).send("Missing OAuth Code and Refresh Token");
@@ -38,7 +39,10 @@ router.post("/", async (req, res) => {
38
39
  const params = new URLSearchParams();
39
40
  params.append("grant_type", "authorization_code");
40
41
  params.append("client_id", providerConfig.clientId);
41
- params.append("client_secret", process.env[`${provider.toUpperCase()}_CLIENT_SECRET`]);
42
+ params.append(
43
+ "client_secret",
44
+ process.env[`${provider.toUpperCase()}_CLIENT_SECRET`]
45
+ );
42
46
  params.append("code", code);
43
47
  params.append("redirect_uri", redirectUri);
44
48
 
@@ -48,35 +52,37 @@ router.post("/", async (req, res) => {
48
52
  {
49
53
  headers: {
50
54
  "Content-Type": "application/x-www-form-urlencoded",
51
- "Accept": "application/json"
55
+ Accept: "application/json",
52
56
  },
53
- timeout: 10000
57
+ timeout: 10000,
54
58
  }
55
59
  );
56
60
 
57
61
  if (tokenResponse.data.error) {
58
- throw new AuthenticationError(
62
+ throw new AuthorizationError(
59
63
  tokenResponse.data.error_description || tokenResponse.data.error
60
64
  );
61
65
  }
62
66
 
63
67
  if (!tokenResponse.data.access_token) {
64
- throw new AuthenticationError("No access token received from OAuth provider");
68
+ throw new AuthenticationError(
69
+ "No access token received from OAuth provider"
70
+ );
65
71
  }
66
72
 
67
73
  accessTokenForAPI = tokenResponse.data.access_token;
68
- newRefreshToken = tokenResponse.data.refresh_token || tokenResponse.data.access_token;
74
+ newRefreshToken =
75
+ tokenResponse.data.refresh_token || tokenResponse.data.access_token;
69
76
  } else {
70
77
  accessTokenForAPI = refreshToken;
71
78
  }
72
79
 
73
-
74
80
  let userResponse = await axios.get(providerConfig.userUrl, {
75
81
  headers: {
76
82
  Authorization: `Bearer ${accessTokenForAPI}`,
77
- "Accept": "application/json"
83
+ Accept: "application/json",
78
84
  },
79
- timeout: 10000
85
+ timeout: 10000,
80
86
  });
81
87
 
82
88
  console.log("User info response:", userResponse.data);
@@ -92,9 +98,11 @@ router.post("/", async (req, res) => {
92
98
  console.error("User identifier extraction failed:", {
93
99
  availableFields: Object.keys(userResponse.data),
94
100
  expectedField: identifierField,
95
- fallbackField: project.oauth.jwt.identifier
101
+ fallbackField: project.oauth.jwt.identifier,
96
102
  });
97
- throw new Error(`Cannot find user identifier in ${provider} OAuth response`);
103
+ throw new Error(
104
+ `Cannot find user identifier in ${provider} OAuth response`
105
+ );
98
106
  }
99
107
 
100
108
  const prefixedUserId = `${provider}_${userId}`;
@@ -113,7 +121,7 @@ router.post("/", async (req, res) => {
113
121
  iss: "nuc",
114
122
  aid: appId,
115
123
  provider: provider,
116
- iat: Math.floor(Date.now() / 1000)
124
+ iat: Math.floor(Date.now() / 1000),
117
125
  },
118
126
  process.env.JWT_SECRET,
119
127
  { expiresIn: "12h" }
@@ -128,7 +136,7 @@ router.post("/", async (req, res) => {
128
136
  aid: appId,
129
137
  rls: permissions.map((permission) => permission.role),
130
138
  provider: provider,
131
- iat: Math.floor(Date.now() / 1000)
139
+ iat: Math.floor(Date.now() / 1000),
132
140
  },
133
141
  process.env.JWT_SECRET,
134
142
  { expiresIn: "12h" }
@@ -141,7 +149,7 @@ router.post("/", async (req, res) => {
141
149
  iss: "nuc",
142
150
  aid: appId,
143
151
  provider: provider,
144
- iat: Math.floor(Date.now() / 1000)
152
+ iat: Math.floor(Date.now() / 1000),
145
153
  },
146
154
  process.env.JWT_SECRET,
147
155
  { expiresIn: "12h" }
@@ -150,16 +158,15 @@ router.post("/", async (req, res) => {
150
158
 
151
159
  res.status(200).json({
152
160
  accessToken,
153
- refreshToken: newRefreshToken
161
+ refreshToken: newRefreshToken,
154
162
  });
155
163
  });
156
164
 
157
165
  router.get("/user", async (req, res) => {
158
166
  const authHeader = req.headers.authorization;
159
- const refreshTokenHeader = req.headers['x-refresh-token'];
160
-
167
+ const refreshTokenHeader = req.headers["x-refresh-token"];
161
168
 
162
- if (!authHeader || !authHeader.startsWith('Bearer ')) {
169
+ if (!authHeader || !authHeader.startsWith("Bearer ")) {
163
170
  return res.status(401).end();
164
171
  }
165
172
 
@@ -167,12 +174,12 @@ router.get("/user", async (req, res) => {
167
174
  return res.status(400).send("Missing refresh token");
168
175
  }
169
176
 
170
- const token = authHeader.split(' ')[1];
171
-
177
+ const token = authHeader.split(" ")[1];
178
+
172
179
  const decoded = jwt.verify(token, process.env.JWT_SECRET);
173
180
  const userId = decoded.sub;
174
181
  const provider = decoded.provider;
175
-
182
+
176
183
  if (!userId || !provider) {
177
184
  return res.status(401).end();
178
185
  }
@@ -182,16 +189,14 @@ router.get("/user", async (req, res) => {
182
189
  return res.status(400).send("Unsupported OAuth provider");
183
190
  }
184
191
 
185
-
186
192
  const userResponse = await axios.get(providerConfig.userUrl, {
187
193
  headers: {
188
194
  Authorization: `Bearer ${refreshTokenHeader}`,
189
- "Accept": "application/json"
195
+ Accept: "application/json",
190
196
  },
191
- timeout: 10000
197
+ timeout: 10000,
192
198
  });
193
199
 
194
-
195
200
  const userFieldMapping = providerConfig.userFields;
196
201
  const userDetails = {
197
202
  id: userId,
@@ -199,12 +204,12 @@ router.get("/user", async (req, res) => {
199
204
  name: userResponse.data[userFieldMapping.name] || null,
200
205
  displayName: userResponse.data[userFieldMapping.displayName] || null,
201
206
  avatarUrl: userResponse.data[userFieldMapping.avatarUrl] || null,
202
- email: userResponse.data[userFieldMapping.email] || null
207
+ email: userResponse.data[userFieldMapping.email] || null,
203
208
  };
204
209
 
205
210
  res.status(200).json({
206
- user: userDetails
211
+ user: userDetails,
207
212
  });
208
213
  });
209
214
 
210
- module.exports = router;
215
+ module.exports = router;
@@ -5,7 +5,7 @@ const app = platform.express();
5
5
 
6
6
  const request = require("supertest");
7
7
  const jwt = require("jsonwebtoken");
8
- const { equal } = require("assert");
8
+ const { equal, deepEqual } = require("assert");
9
9
  const config = require("../../config");
10
10
  const { project } = config();
11
11
 
@@ -19,14 +19,16 @@ describe("OAuth", () => {
19
19
  });
20
20
 
21
21
  it("returns accessToken and refreshToken with code", async () => {
22
- mock
23
- .onPost(project.oauth.tokenUrl)
24
- .reply(
25
- 200,
26
- "access_token=c9Q2KuluvCGdM4YZiUnGWxImvuFnbv&scope=user&token_type=bearer"
27
- );
22
+ const provider = "github";
23
+ const providerConfig = project.oauth.providers[provider];
24
+
25
+ mock.onPost(providerConfig.tokenUrl).reply(200, {
26
+ access_token: "c9Q2KuluvCGdM4YZiUnGWxImvuFnbv",
27
+ token_type: "bearer",
28
+ scope: "user",
29
+ });
28
30
 
29
- mock.onGet(project.oauth.userUrl).reply(200, { email: "1001" });
31
+ mock.onGet(providerConfig.userUrl).reply(200, { id: "1001" });
30
32
 
31
33
  const {
32
34
  body: { accessToken, refreshToken },
@@ -35,8 +37,9 @@ describe("OAuth", () => {
35
37
  .send({
36
38
  appId: "977f5f57-8936-4388-8eb0-00a512cf01cc",
37
39
  projectId: "cb16e069-6214-47f1-9922-1f7fe7629525",
38
- redirectUri: project.oauth.redirectUri,
40
+ redirectUri: providerConfig.redirectUri,
39
41
  code: "vImIDQtMVcYnUCI3Brp6",
42
+ provider: provider,
40
43
  })
41
44
  .expect(200);
42
45
 
@@ -44,17 +47,21 @@ describe("OAuth", () => {
44
47
 
45
48
  equal(payload.iss, "nuc");
46
49
  equal(payload.aud, "cb16e069-6214-47f1-9922-1f7fe7629525");
47
- equal(payload.sub, "1001");
48
- equal(payload.rls, "OWNER");
50
+ equal(payload.sub, `${provider}_1001`);
51
+ deepEqual(payload.rls, ["OWNER"]);
49
52
  equal(payload.aid, "977f5f57-8936-4388-8eb0-00a512cf01cc");
50
53
  equal(payload.oid, "dfb990bb-81dd-4584-82ce-050eb8f6a12f");
54
+ equal(payload.provider, provider);
51
55
  equal(refreshToken, "c9Q2KuluvCGdM4YZiUnGWxImvuFnbv");
52
56
  });
53
57
 
54
58
  it("returns accessToken and refreshToken with refresh token", async () => {
59
+ const provider = "github";
60
+ const providerConfig = project.oauth.providers[provider];
61
+
55
62
  mock
56
- .onGet(project.oauth.userUrl)
57
- .reply(200, { email: "liam@rebellioncoffee.shop" });
63
+ .onGet(providerConfig.userUrl)
64
+ .reply(200, { id: "liam@rebellioncoffee.shop" });
58
65
 
59
66
  const {
60
67
  body: { accessToken, refreshToken },
@@ -63,42 +70,59 @@ describe("OAuth", () => {
63
70
  .send({
64
71
  appId: "977f5f57-8936-4388-8eb0-00a512cf01cc",
65
72
  refreshToken: "lzk7FZGga5hHrfiAePtswijiJHIOev",
73
+ provider: provider,
66
74
  })
67
75
  .expect(200);
68
76
 
69
77
  const payload = jwt.decode(accessToken);
70
78
 
71
- equal(payload.sub, "liam@rebellioncoffee.shop");
79
+ equal(payload.sub, `${provider}_liam@rebellioncoffee.shop`);
72
80
  equal(payload.iss, "nuc");
81
+ equal(payload.provider, provider);
73
82
  equal(refreshToken, "lzk7FZGga5hHrfiAePtswijiJHIOev");
74
83
  });
75
84
 
76
85
  it("returns 400 if code and refreshToken are missing", async () => {
77
- await request(app).post("/oauth").send({}).expect(400);
86
+ await request(app)
87
+ .post("/oauth")
88
+ .send({
89
+ appId: "977f5f57-8936-4388-8eb0-00a512cf01cc",
90
+ provider: "github",
91
+ })
92
+ .expect(400);
78
93
  });
79
94
 
80
95
  it("returns 401 if code is invalid", async () => {
81
- mock
82
- .onPost(project.oauth.tokenUrl)
83
- .reply(200, "error=bad_verification_code");
84
- mock.onGet(project.oauth.userUrl).reply(401);
96
+ const provider = "github";
97
+ const providerConfig = project.oauth.providers[provider];
98
+
99
+ mock.onPost(providerConfig.tokenUrl).reply(200, {
100
+ error: "bad_verification_code",
101
+ });
102
+ mock.onGet(providerConfig.userUrl).reply(401);
85
103
 
86
104
  const res = await request(app).post("/oauth").send({
87
105
  appId: "977f5f57-8936-4388-8eb0-00a512cf01cc",
88
106
  code: "ZpodRqsLu2EJxbVrcqnV",
107
+ redirectUri: providerConfig.redirectUri,
108
+ provider: provider,
89
109
  });
90
110
  equal(res.status, 401);
91
111
  });
92
112
 
93
113
  it("returns 503 if OAuth Provider is not accessible", async () => {
94
- mock.onPost(project.oauth.tokenUrl).networkError();
95
- mock.onGet(project.oauth.userUrl).networkError();
114
+ const provider = "github";
115
+ const providerConfig = project.oauth.providers[provider];
116
+
117
+ mock.onPost(providerConfig.tokenUrl).networkError();
118
+ mock.onGet(providerConfig.userUrl).networkError();
96
119
 
97
120
  await request(app)
98
121
  .post("/oauth")
99
122
  .send({
100
123
  appId: "977f5f57-8936-4388-8eb0-00a512cf01cc",
101
124
  refreshToken: "WnhGHF55s6HFRgpRL9AcV2N2VcYemj",
125
+ provider: provider,
102
126
  })
103
127
  .expect(503);
104
128
 
@@ -107,6 +131,8 @@ describe("OAuth", () => {
107
131
  .send({
108
132
  appId: "977f5f57-8936-4388-8eb0-00a512cf01cc",
109
133
  code: "RwlaK2waOdbAa4tt19RF",
134
+ redirectUri: providerConfig.redirectUri,
135
+ provider: provider,
110
136
  })
111
137
  .expect(503);
112
138
  });
@@ -38,6 +38,14 @@ describe("Permissions", () => {
38
38
  userId: "1001",
39
39
  role: "OWNER",
40
40
  },
41
+ {
42
+ id: "f81887da-d05f-4959-9def-6cd137857099",
43
+ appId: "977f5f57-8936-4388-8eb0-00a512cf01cc",
44
+ organizationId: "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
45
+ projectId: "cb16e069-6214-47f1-9922-1f7fe7629525",
46
+ userId: "github_1001",
47
+ role: "OWNER",
48
+ },
41
49
  {
42
50
  id: "a1b60c53-66e2-4034-8654-38b83577f279",
43
51
  appId: "977f5f57-8936-4388-8eb0-00a512cf01cc",
@@ -88,6 +96,14 @@ describe("Permissions", () => {
88
96
  userId: "1001",
89
97
  role: "OWNER",
90
98
  },
99
+ {
100
+ id: "f81887da-d05f-4959-9def-6cd137857099",
101
+ appId: "977f5f57-8936-4388-8eb0-00a512cf01cc",
102
+ organizationId: "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
103
+ projectId: "cb16e069-6214-47f1-9922-1f7fe7629525",
104
+ userId: "github_1001",
105
+ role: "OWNER",
106
+ },
91
107
  {
92
108
  id: "a1b60c53-66e2-4034-8654-38b83577f279",
93
109
  appId: "977f5f57-8936-4388-8eb0-00a512cf01cc",
@@ -125,6 +141,14 @@ describe("Permissions", () => {
125
141
  .expect(200);
126
142
 
127
143
  deepEqual(permissions, [
144
+ {
145
+ id: "f81887da-d05f-4959-9def-6cd137857099",
146
+ appId: "977f5f57-8936-4388-8eb0-00a512cf01cc",
147
+ organizationId: "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
148
+ projectId: "cb16e069-6214-47f1-9922-1f7fe7629525",
149
+ userId: "github_1001",
150
+ role: "OWNER",
151
+ },
128
152
  {
129
153
  id: "a1b60c53-66e2-4034-8654-38b83577f279",
130
154
  appId: "977f5f57-8936-4388-8eb0-00a512cf01cc",
@@ -1,165 +1,173 @@
1
1
  {
2
- "sequence": 9007199254740991,
3
- "seed": [
4
- {
5
- "id": "e81887da-d05f-4959-9def-6cd137857088",
6
- "appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
7
- "organizationId": "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
8
- "projectId": "cb16e069-6214-47f1-9922-1f7fe7629525",
9
- "userId": "1001",
10
- "role": "OWNER"
11
- },
12
- {
13
- "id": "b8e498d4-2d79-4e6e-b098-6a97e1d89a94",
14
- "appId": "10b7bc8c-a49c-4002-b0ec-63599e4b5210",
15
- "organizationId": "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
16
- "projectId": "add6dfa4-45ba-4da2-bc5c-5a529610b52f",
17
- "userId": "1001",
18
- "role": "OWNER"
19
- },
20
- {
21
- "id": "30044ea7-aa19-4696-876b-26fa76bb91f3",
22
- "appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
23
- "organizationId": "1c063446-7e78-432a-a273-34f481d0f0c3",
24
- "projectId": "0c756054-2d28-4f87-9b12-8023a79136a5",
25
- "userId": "1001",
26
- "role": "OWNER"
27
- },
28
- {
29
- "id": "973dfaff-0718-4d2d-a714-587cf7a44b98",
30
- "appId": "10b7bc8c-a49c-4002-b0ec-63599e4b5210",
31
- "organizationId": "1c063446-7e78-432a-a273-34f481d0f0c3",
32
- "projectId": "e6d4744d-a11b-4c75-acad-e24a02903729",
33
- "userId": "1001",
34
- "role": "OWNER"
35
- },
36
- {
37
- "id": "4ecc380a-b480-4faa-ad47-878dd2ee4264",
38
- "appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
39
- "organizationId": "5459ab03-204a-4627-bdde-667b7802cb35",
40
- "projectId": "21d2530b-4657-4ac0-b8cd-1a9f82786e32",
41
- "userId": "1001",
42
- "role": "OWNER"
43
- },
44
- {
45
- "id": "a1b60c53-66e2-4034-8654-38b83577f279",
46
- "appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
47
- "organizationId": "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
48
- "projectId": "cb16e069-6214-47f1-9922-1f7fe7629525",
49
- "userId": "49736917",
50
- "role": "OWNER"
51
- },
52
- {
53
- "id": "e2809e32-b025-4592-855f-dd2b8f49e1b2",
54
- "appId": "10b7bc8c-a49c-4002-b0ec-63599e4b5210",
55
- "organizationId": "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
56
- "projectId": "add6dfa4-45ba-4da2-bc5c-5a529610b52f",
57
- "userId": "49736917",
58
- "role": "OWNER"
59
- },
60
- {
61
- "id": "9fc7dd4e-97ef-47a5-987c-99f8015fc736",
62
- "appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
63
- "organizationId": "1c063446-7e78-432a-a273-34f481d0f0c3",
64
- "projectId": "0c756054-2d28-4f87-9b12-8023a79136a5",
65
- "userId": "49736917",
66
- "role": "OWNER"
67
- },
68
- {
69
- "id": "b8302e81-4a44-4358-978f-21e9219ead61",
70
- "appId": "10b7bc8c-a49c-4002-b0ec-63599e4b5210",
71
- "organizationId": "1c063446-7e78-432a-a273-34f481d0f0c3",
72
- "projectId": "e6d4744d-a11b-4c75-acad-e24a02903729",
73
- "userId": "49736917",
74
- "role": "OWNER"
75
- },
76
- {
77
- "id": "4758a390-4968-44bd-aafe-abdee8044a01",
78
- "appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
79
- "organizationId": "5459ab03-204a-4627-bdde-667b7802cb35",
80
- "projectId": "21d2530b-4657-4ac0-b8cd-1a9f82786e32",
81
- "userId": "49736917",
82
- "role": "OWNER"
83
- },
84
- {
85
- "id": "38b1cc0c-46d8-4f95-9be9-0df1a6c91d7b",
86
- "appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
87
- "organizationId": "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
88
- "projectId": "cb16e069-6214-47f1-9922-1f7fe7629525",
89
- "userId": "54210920",
90
- "role": "OWNER"
91
- },
92
- {
93
- "id": "03a1eb7b-b25a-4b44-9484-f8b93d8a9e5b",
94
- "appId": "10b7bc8c-a49c-4002-b0ec-63599e4b5210",
95
- "organizationId": "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
96
- "projectId": "add6dfa4-45ba-4da2-bc5c-5a529610b52f",
97
- "userId": "54210920",
98
- "role": "OWNER"
99
- },
100
- {
101
- "id": "e54b340d-e1d7-452d-8422-13cae24b0a9f",
102
- "appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
103
- "organizationId": "1c063446-7e78-432a-a273-34f481d0f0c3",
104
- "projectId": "0c756054-2d28-4f87-9b12-8023a79136a5",
105
- "userId": "54210920",
106
- "role": "OWNER"
107
- },
108
- {
109
- "id": "fce2b3bb-2776-43d8-bb35-14633882b899",
110
- "appId": "10b7bc8c-a49c-4002-b0ec-63599e4b5210",
111
- "organizationId": "1c063446-7e78-432a-a273-34f481d0f0c3",
112
- "projectId": "e6d4744d-a11b-4c75-acad-e24a02903729",
113
- "userId": "54210920",
114
- "role": "OWNER"
115
- },
116
- {
117
- "id": "9067f420-9c22-4578-81b6-aa0d88213f24",
118
- "appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
119
- "organizationId": "5459ab03-204a-4627-bdde-667b7802cb35",
120
- "projectId": "21d2530b-4657-4ac0-b8cd-1a9f82786e32",
121
- "userId": "54210920",
122
- "role": "OWNER"
123
- },
124
- {
125
- "id": "7f7bd2c8-3c27-455c-814e-1874e96246ed",
126
- "appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
127
- "organizationId": "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
128
- "projectId": "cb16e069-6214-47f1-9922-1f7fe7629525",
129
- "userId": "90180086",
130
- "role": "OWNER"
131
- },
132
- {
133
- "id": "f09e5539-a983-424c-943f-f9c0e5cffa4e",
134
- "appId": "10b7bc8c-a49c-4002-b0ec-63599e4b5210",
135
- "organizationId": "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
136
- "projectId": "add6dfa4-45ba-4da2-bc5c-5a529610b52f",
137
- "userId": "90180086",
138
- "role": "OWNER"
139
- },
140
- {
141
- "id": "bd4d6afe-4592-4739-84af-011760879b3d",
142
- "appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
143
- "organizationId": "1c063446-7e78-432a-a273-34f481d0f0c3",
144
- "projectId": "0c756054-2d28-4f87-9b12-8023a79136a5",
145
- "userId": "90180086",
146
- "role": "OWNER"
147
- },
148
- {
149
- "id": "5c76772d-40af-464d-ae35-4415bbddc3cf",
150
- "appId": "10b7bc8c-a49c-4002-b0ec-63599e4b5210",
151
- "organizationId": "1c063446-7e78-432a-a273-34f481d0f0c3",
152
- "projectId": "e6d4744d-a11b-4c75-acad-e24a02903729",
153
- "userId": "90180086",
154
- "role": "OWNER"
155
- },
156
- {
157
- "id": "20d0920f-00bb-404f-a01e-1ab40eaa8583",
158
- "appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
159
- "organizationId": "5459ab03-204a-4627-bdde-667b7802cb35",
160
- "projectId": "21d2530b-4657-4ac0-b8cd-1a9f82786e32",
161
- "userId": "90180086",
162
- "role": "OWNER"
163
- }
164
- ]
165
- }
2
+ "sequence": 9007199254740991,
3
+ "seed": [
4
+ {
5
+ "id": "e81887da-d05f-4959-9def-6cd137857088",
6
+ "appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
7
+ "organizationId": "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
8
+ "projectId": "cb16e069-6214-47f1-9922-1f7fe7629525",
9
+ "userId": "1001",
10
+ "role": "OWNER"
11
+ },
12
+ {
13
+ "id": "f81887da-d05f-4959-9def-6cd137857099",
14
+ "appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
15
+ "organizationId": "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
16
+ "projectId": "cb16e069-6214-47f1-9922-1f7fe7629525",
17
+ "userId": "github_1001",
18
+ "role": "OWNER"
19
+ },
20
+ {
21
+ "id": "b8e498d4-2d79-4e6e-b098-6a97e1d89a94",
22
+ "appId": "10b7bc8c-a49c-4002-b0ec-63599e4b5210",
23
+ "organizationId": "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
24
+ "projectId": "add6dfa4-45ba-4da2-bc5c-5a529610b52f",
25
+ "userId": "1001",
26
+ "role": "OWNER"
27
+ },
28
+ {
29
+ "id": "30044ea7-aa19-4696-876b-26fa76bb91f3",
30
+ "appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
31
+ "organizationId": "1c063446-7e78-432a-a273-34f481d0f0c3",
32
+ "projectId": "0c756054-2d28-4f87-9b12-8023a79136a5",
33
+ "userId": "1001",
34
+ "role": "OWNER"
35
+ },
36
+ {
37
+ "id": "973dfaff-0718-4d2d-a714-587cf7a44b98",
38
+ "appId": "10b7bc8c-a49c-4002-b0ec-63599e4b5210",
39
+ "organizationId": "1c063446-7e78-432a-a273-34f481d0f0c3",
40
+ "projectId": "e6d4744d-a11b-4c75-acad-e24a02903729",
41
+ "userId": "1001",
42
+ "role": "OWNER"
43
+ },
44
+ {
45
+ "id": "4ecc380a-b480-4faa-ad47-878dd2ee4264",
46
+ "appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
47
+ "organizationId": "5459ab03-204a-4627-bdde-667b7802cb35",
48
+ "projectId": "21d2530b-4657-4ac0-b8cd-1a9f82786e32",
49
+ "userId": "1001",
50
+ "role": "OWNER"
51
+ },
52
+ {
53
+ "id": "a1b60c53-66e2-4034-8654-38b83577f279",
54
+ "appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
55
+ "organizationId": "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
56
+ "projectId": "cb16e069-6214-47f1-9922-1f7fe7629525",
57
+ "userId": "49736917",
58
+ "role": "OWNER"
59
+ },
60
+ {
61
+ "id": "e2809e32-b025-4592-855f-dd2b8f49e1b2",
62
+ "appId": "10b7bc8c-a49c-4002-b0ec-63599e4b5210",
63
+ "organizationId": "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
64
+ "projectId": "add6dfa4-45ba-4da2-bc5c-5a529610b52f",
65
+ "userId": "49736917",
66
+ "role": "OWNER"
67
+ },
68
+ {
69
+ "id": "9fc7dd4e-97ef-47a5-987c-99f8015fc736",
70
+ "appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
71
+ "organizationId": "1c063446-7e78-432a-a273-34f481d0f0c3",
72
+ "projectId": "0c756054-2d28-4f87-9b12-8023a79136a5",
73
+ "userId": "49736917",
74
+ "role": "OWNER"
75
+ },
76
+ {
77
+ "id": "b8302e81-4a44-4358-978f-21e9219ead61",
78
+ "appId": "10b7bc8c-a49c-4002-b0ec-63599e4b5210",
79
+ "organizationId": "1c063446-7e78-432a-a273-34f481d0f0c3",
80
+ "projectId": "e6d4744d-a11b-4c75-acad-e24a02903729",
81
+ "userId": "49736917",
82
+ "role": "OWNER"
83
+ },
84
+ {
85
+ "id": "4758a390-4968-44bd-aafe-abdee8044a01",
86
+ "appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
87
+ "organizationId": "5459ab03-204a-4627-bdde-667b7802cb35",
88
+ "projectId": "21d2530b-4657-4ac0-b8cd-1a9f82786e32",
89
+ "userId": "49736917",
90
+ "role": "OWNER"
91
+ },
92
+ {
93
+ "id": "38b1cc0c-46d8-4f95-9be9-0df1a6c91d7b",
94
+ "appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
95
+ "organizationId": "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
96
+ "projectId": "cb16e069-6214-47f1-9922-1f7fe7629525",
97
+ "userId": "54210920",
98
+ "role": "OWNER"
99
+ },
100
+ {
101
+ "id": "03a1eb7b-b25a-4b44-9484-f8b93d8a9e5b",
102
+ "appId": "10b7bc8c-a49c-4002-b0ec-63599e4b5210",
103
+ "organizationId": "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
104
+ "projectId": "add6dfa4-45ba-4da2-bc5c-5a529610b52f",
105
+ "userId": "54210920",
106
+ "role": "OWNER"
107
+ },
108
+ {
109
+ "id": "e54b340d-e1d7-452d-8422-13cae24b0a9f",
110
+ "appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
111
+ "organizationId": "1c063446-7e78-432a-a273-34f481d0f0c3",
112
+ "projectId": "0c756054-2d28-4f87-9b12-8023a79136a5",
113
+ "userId": "54210920",
114
+ "role": "OWNER"
115
+ },
116
+ {
117
+ "id": "fce2b3bb-2776-43d8-bb35-14633882b899",
118
+ "appId": "10b7bc8c-a49c-4002-b0ec-63599e4b5210",
119
+ "organizationId": "1c063446-7e78-432a-a273-34f481d0f0c3",
120
+ "projectId": "e6d4744d-a11b-4c75-acad-e24a02903729",
121
+ "userId": "54210920",
122
+ "role": "OWNER"
123
+ },
124
+ {
125
+ "id": "9067f420-9c22-4578-81b6-aa0d88213f24",
126
+ "appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
127
+ "organizationId": "5459ab03-204a-4627-bdde-667b7802cb35",
128
+ "projectId": "21d2530b-4657-4ac0-b8cd-1a9f82786e32",
129
+ "userId": "54210920",
130
+ "role": "OWNER"
131
+ },
132
+ {
133
+ "id": "7f7bd2c8-3c27-455c-814e-1874e96246ed",
134
+ "appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
135
+ "organizationId": "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
136
+ "projectId": "cb16e069-6214-47f1-9922-1f7fe7629525",
137
+ "userId": "90180086",
138
+ "role": "OWNER"
139
+ },
140
+ {
141
+ "id": "f09e5539-a983-424c-943f-f9c0e5cffa4e",
142
+ "appId": "10b7bc8c-a49c-4002-b0ec-63599e4b5210",
143
+ "organizationId": "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
144
+ "projectId": "add6dfa4-45ba-4da2-bc5c-5a529610b52f",
145
+ "userId": "90180086",
146
+ "role": "OWNER"
147
+ },
148
+ {
149
+ "id": "bd4d6afe-4592-4739-84af-011760879b3d",
150
+ "appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
151
+ "organizationId": "1c063446-7e78-432a-a273-34f481d0f0c3",
152
+ "projectId": "0c756054-2d28-4f87-9b12-8023a79136a5",
153
+ "userId": "90180086",
154
+ "role": "OWNER"
155
+ },
156
+ {
157
+ "id": "5c76772d-40af-464d-ae35-4415bbddc3cf",
158
+ "appId": "10b7bc8c-a49c-4002-b0ec-63599e4b5210",
159
+ "organizationId": "1c063446-7e78-432a-a273-34f481d0f0c3",
160
+ "projectId": "e6d4744d-a11b-4c75-acad-e24a02903729",
161
+ "userId": "90180086",
162
+ "role": "OWNER"
163
+ },
164
+ {
165
+ "id": "20d0920f-00bb-404f-a01e-1ab40eaa8583",
166
+ "appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
167
+ "organizationId": "5459ab03-204a-4627-bdde-667b7802cb35",
168
+ "projectId": "21d2530b-4657-4ac0-b8cd-1a9f82786e32",
169
+ "userId": "90180086",
170
+ "role": "OWNER"
171
+ }
172
+ ]
173
+ }