@canmingir/link-express 1.6.1 → 1.6.3

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.3",
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,28 +98,28 @@ 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
- const prefixedUserId = `${provider}_${userId}`;
101
-
102
108
  let accessToken;
103
109
 
104
110
  if (projectId) {
105
111
  const permissions = await Permission.findAll({
106
- where: { userId: prefixedUserId, projectId, appId },
112
+ where: { userId, projectId, appId },
107
113
  });
108
114
 
109
115
  if (!permissions.length) {
110
116
  accessToken = jwt.sign(
111
117
  {
112
- sub: prefixedUserId,
118
+ sub: userId,
113
119
  iss: "nuc",
114
120
  aid: appId,
115
121
  provider: provider,
116
- iat: Math.floor(Date.now() / 1000)
122
+ iat: Math.floor(Date.now() / 1000),
117
123
  },
118
124
  process.env.JWT_SECRET,
119
125
  { expiresIn: "12h" }
@@ -121,14 +127,14 @@ router.post("/", async (req, res) => {
121
127
  } else {
122
128
  accessToken = jwt.sign(
123
129
  {
124
- sub: prefixedUserId,
130
+ sub: userId,
125
131
  iss: "nuc",
126
132
  aud: projectId,
127
133
  oid: permissions[0].organizationId,
128
134
  aid: appId,
129
135
  rls: permissions.map((permission) => permission.role),
130
136
  provider: provider,
131
- iat: Math.floor(Date.now() / 1000)
137
+ iat: Math.floor(Date.now() / 1000),
132
138
  },
133
139
  process.env.JWT_SECRET,
134
140
  { expiresIn: "12h" }
@@ -137,11 +143,11 @@ router.post("/", async (req, res) => {
137
143
  } else {
138
144
  accessToken = jwt.sign(
139
145
  {
140
- sub: prefixedUserId,
146
+ sub: userId,
141
147
  iss: "nuc",
142
148
  aid: appId,
143
149
  provider: provider,
144
- iat: Math.floor(Date.now() / 1000)
150
+ iat: Math.floor(Date.now() / 1000),
145
151
  },
146
152
  process.env.JWT_SECRET,
147
153
  { expiresIn: "12h" }
@@ -150,16 +156,15 @@ router.post("/", async (req, res) => {
150
156
 
151
157
  res.status(200).json({
152
158
  accessToken,
153
- refreshToken: newRefreshToken
159
+ refreshToken: newRefreshToken,
154
160
  });
155
161
  });
156
162
 
157
163
  router.get("/user", async (req, res) => {
158
164
  const authHeader = req.headers.authorization;
159
- const refreshTokenHeader = req.headers['x-refresh-token'];
160
-
165
+ const refreshTokenHeader = req.headers["x-refresh-token"];
161
166
 
162
- if (!authHeader || !authHeader.startsWith('Bearer ')) {
167
+ if (!authHeader || !authHeader.startsWith("Bearer ")) {
163
168
  return res.status(401).end();
164
169
  }
165
170
 
@@ -167,12 +172,12 @@ router.get("/user", async (req, res) => {
167
172
  return res.status(400).send("Missing refresh token");
168
173
  }
169
174
 
170
- const token = authHeader.split(' ')[1];
171
-
175
+ const token = authHeader.split(" ")[1];
176
+
172
177
  const decoded = jwt.verify(token, process.env.JWT_SECRET);
173
178
  const userId = decoded.sub;
174
179
  const provider = decoded.provider;
175
-
180
+
176
181
  if (!userId || !provider) {
177
182
  return res.status(401).end();
178
183
  }
@@ -182,16 +187,14 @@ router.get("/user", async (req, res) => {
182
187
  return res.status(400).send("Unsupported OAuth provider");
183
188
  }
184
189
 
185
-
186
190
  const userResponse = await axios.get(providerConfig.userUrl, {
187
191
  headers: {
188
192
  Authorization: `Bearer ${refreshTokenHeader}`,
189
- "Accept": "application/json"
193
+ Accept: "application/json",
190
194
  },
191
- timeout: 10000
195
+ timeout: 10000,
192
196
  });
193
197
 
194
-
195
198
  const userFieldMapping = providerConfig.userFields;
196
199
  const userDetails = {
197
200
  id: userId,
@@ -199,12 +202,12 @@ router.get("/user", async (req, res) => {
199
202
  name: userResponse.data[userFieldMapping.name] || null,
200
203
  displayName: userResponse.data[userFieldMapping.displayName] || null,
201
204
  avatarUrl: userResponse.data[userFieldMapping.avatarUrl] || null,
202
- email: userResponse.data[userFieldMapping.email] || null
205
+ email: userResponse.data[userFieldMapping.email] || null,
203
206
  };
204
207
 
205
208
  res.status(200).json({
206
- user: userDetails
209
+ user: userDetails,
207
210
  });
208
211
  });
209
212
 
210
- module.exports = router;
213
+ 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, `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, `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
  });
@@ -1,165 +1,165 @@
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": "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
+ }