@rebasepro/server-core 0.0.1-canary.4d4fb3e → 0.0.1-canary.ca2cb6e

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.
Files changed (176) hide show
  1. package/dist/common/src/collections/CollectionRegistry.d.ts +8 -0
  2. package/dist/common/src/util/entities.d.ts +22 -0
  3. package/dist/common/src/util/relations.d.ts +14 -4
  4. package/dist/common/src/util/resolutions.d.ts +1 -1
  5. package/dist/index-DXVBFp5V.js +37 -0
  6. package/dist/index-DXVBFp5V.js.map +1 -0
  7. package/dist/index.es.js +49931 -55
  8. package/dist/index.es.js.map +1 -1
  9. package/dist/index.umd.js +28475 -34569
  10. package/dist/index.umd.js.map +1 -1
  11. package/dist/server-core/src/api/openapi-generator.d.ts +15 -1
  12. package/dist/server-core/src/api/types.d.ts +1 -1
  13. package/dist/server-core/src/auth/admin-routes.d.ts +10 -1
  14. package/dist/server-core/src/auth/apple-oauth.d.ts +30 -0
  15. package/dist/server-core/src/auth/bitbucket-oauth.d.ts +11 -0
  16. package/dist/server-core/src/auth/discord-oauth.d.ts +14 -0
  17. package/dist/server-core/src/auth/facebook-oauth.d.ts +14 -0
  18. package/dist/server-core/src/auth/github-oauth.d.ts +15 -0
  19. package/dist/server-core/src/auth/gitlab-oauth.d.ts +13 -0
  20. package/dist/server-core/src/auth/google-oauth.d.ts +5 -11
  21. package/dist/server-core/src/auth/index.d.ts +13 -2
  22. package/dist/server-core/src/auth/interfaces.d.ts +45 -6
  23. package/dist/server-core/src/auth/jwt.d.ts +1 -0
  24. package/dist/server-core/src/auth/linkedin-oauth.d.ts +18 -0
  25. package/dist/server-core/src/auth/microsoft-oauth.d.ts +16 -0
  26. package/dist/server-core/src/auth/middleware.d.ts +36 -11
  27. package/dist/server-core/src/auth/rate-limiter.d.ts +2 -2
  28. package/dist/server-core/src/auth/routes.d.ts +13 -3
  29. package/dist/server-core/src/auth/slack-oauth.d.ts +12 -0
  30. package/dist/server-core/src/auth/spotify-oauth.d.ts +12 -0
  31. package/dist/server-core/src/auth/twitter-oauth.d.ts +18 -0
  32. package/dist/server-core/src/cron/cron-loader.d.ts +17 -0
  33. package/dist/server-core/src/cron/cron-routes.d.ts +14 -0
  34. package/dist/server-core/src/cron/cron-scheduler.d.ts +61 -0
  35. package/dist/server-core/src/cron/cron-store.d.ts +32 -0
  36. package/dist/server-core/src/cron/index.d.ts +6 -0
  37. package/dist/server-core/src/email/index.d.ts +2 -2
  38. package/dist/server-core/src/email/templates.d.ts +9 -0
  39. package/dist/server-core/src/email/types.d.ts +20 -23
  40. package/dist/server-core/src/history/history-routes.d.ts +2 -2
  41. package/dist/server-core/src/index.d.ts +5 -0
  42. package/dist/server-core/src/init.d.ts +112 -2
  43. package/dist/server-core/src/singleton.d.ts +35 -0
  44. package/dist/server-core/src/storage/LocalStorageController.d.ts +9 -9
  45. package/dist/server-core/src/storage/S3StorageController.d.ts +8 -8
  46. package/dist/server-core/src/storage/index.d.ts +18 -11
  47. package/dist/server-core/src/storage/routes.d.ts +3 -3
  48. package/dist/server-core/src/storage/types.d.ts +28 -16
  49. package/dist/server-core/src/utils/dev-port.d.ts +35 -0
  50. package/dist/server-core/src/utils/logger.d.ts +31 -0
  51. package/dist/server-core/src/utils/request-logger.d.ts +19 -0
  52. package/dist/types/src/controllers/auth.d.ts +2 -0
  53. package/dist/types/src/controllers/client.d.ts +119 -7
  54. package/dist/types/src/controllers/collection_registry.d.ts +4 -3
  55. package/dist/types/src/controllers/customization_controller.d.ts +7 -1
  56. package/dist/types/src/controllers/data.d.ts +34 -7
  57. package/dist/types/src/controllers/data_driver.d.ts +20 -28
  58. package/dist/types/src/controllers/database_admin.d.ts +2 -2
  59. package/dist/types/src/controllers/email.d.ts +34 -0
  60. package/dist/types/src/controllers/index.d.ts +1 -0
  61. package/dist/types/src/controllers/local_config_persistence.d.ts +4 -4
  62. package/dist/types/src/controllers/navigation.d.ts +5 -5
  63. package/dist/types/src/controllers/registry.d.ts +6 -3
  64. package/dist/types/src/controllers/side_entity_controller.d.ts +7 -6
  65. package/dist/types/src/controllers/storage.d.ts +24 -26
  66. package/dist/types/src/rebase_context.d.ts +8 -4
  67. package/dist/types/src/types/backend.d.ts +4 -1
  68. package/dist/types/src/types/builders.d.ts +5 -4
  69. package/dist/types/src/types/chips.d.ts +1 -1
  70. package/dist/types/src/types/collections.d.ts +169 -125
  71. package/dist/types/src/types/cron.d.ts +102 -0
  72. package/dist/types/src/types/data_source.d.ts +1 -1
  73. package/dist/types/src/types/entity_actions.d.ts +8 -8
  74. package/dist/types/src/types/entity_callbacks.d.ts +15 -15
  75. package/dist/types/src/types/entity_link_builder.d.ts +1 -1
  76. package/dist/types/src/types/entity_overrides.d.ts +2 -1
  77. package/dist/types/src/types/entity_views.d.ts +8 -8
  78. package/dist/types/src/types/export_import.d.ts +3 -3
  79. package/dist/types/src/types/index.d.ts +1 -0
  80. package/dist/types/src/types/plugins.d.ts +72 -18
  81. package/dist/types/src/types/properties.d.ts +118 -33
  82. package/dist/types/src/types/relations.d.ts +1 -1
  83. package/dist/types/src/types/slots.d.ts +30 -6
  84. package/dist/types/src/types/translations.d.ts +44 -0
  85. package/dist/types/src/types/user_management_delegate.d.ts +1 -0
  86. package/package.json +84 -84
  87. package/scratch.ts +6 -5
  88. package/src/api/ast-schema-editor.ts +11 -11
  89. package/src/api/collections_for_test/callbacks_test_collection.ts +5 -2
  90. package/src/api/errors.ts +38 -14
  91. package/src/api/graphql/graphql-schema-generator.ts +5 -3
  92. package/src/api/openapi-generator.ts +613 -58
  93. package/src/api/rest/api-generator.ts +17 -11
  94. package/src/api/rest/query-parser.ts +1 -1
  95. package/src/api/schema-editor-routes.ts +2 -0
  96. package/src/api/server.ts +8 -5
  97. package/src/api/types.ts +1 -1
  98. package/src/auth/admin-routes.ts +58 -17
  99. package/src/auth/apple-oauth.ts +130 -0
  100. package/src/auth/bitbucket-oauth.ts +82 -0
  101. package/src/auth/discord-oauth.ts +83 -0
  102. package/src/auth/facebook-oauth.ts +72 -0
  103. package/src/auth/github-oauth.ts +110 -0
  104. package/src/auth/gitlab-oauth.ts +70 -0
  105. package/src/auth/google-oauth.ts +34 -46
  106. package/src/auth/index.ts +15 -2
  107. package/src/auth/interfaces.ts +54 -7
  108. package/src/auth/jwt.ts +22 -5
  109. package/src/auth/linkedin-oauth.ts +81 -0
  110. package/src/auth/microsoft-oauth.ts +88 -0
  111. package/src/auth/middleware.ts +194 -45
  112. package/src/auth/password.ts +3 -1
  113. package/src/auth/rate-limiter.ts +4 -4
  114. package/src/auth/routes.ts +197 -139
  115. package/src/auth/slack-oauth.ts +71 -0
  116. package/src/auth/spotify-oauth.ts +67 -0
  117. package/src/auth/twitter-oauth.ts +120 -0
  118. package/src/collections/loader.ts +6 -6
  119. package/src/cron/cron-loader.ts +89 -0
  120. package/src/cron/cron-routes.test.ts +265 -0
  121. package/src/cron/cron-routes.ts +85 -0
  122. package/src/cron/cron-scheduler.test.ts +421 -0
  123. package/src/cron/cron-scheduler.ts +413 -0
  124. package/src/cron/cron-store.ts +163 -0
  125. package/src/cron/index.ts +6 -0
  126. package/src/db/interfaces.ts +2 -2
  127. package/src/email/index.ts +3 -2
  128. package/src/email/smtp-email-service.ts +5 -2
  129. package/src/email/templates.ts +93 -6
  130. package/src/email/types.ts +17 -24
  131. package/src/functions/function-loader.ts +34 -6
  132. package/src/functions/function-routes.ts +2 -2
  133. package/src/history/history-routes.ts +4 -3
  134. package/src/index.ts +10 -0
  135. package/src/init.ts +475 -57
  136. package/src/services/driver-registry.ts +1 -1
  137. package/src/singleton.test.ts +28 -0
  138. package/src/singleton.ts +70 -0
  139. package/src/storage/LocalStorageController.ts +50 -53
  140. package/src/storage/S3StorageController.ts +49 -46
  141. package/src/storage/index.ts +27 -16
  142. package/src/storage/routes.ts +76 -59
  143. package/src/storage/storage-registry.ts +5 -5
  144. package/src/storage/types.ts +44 -32
  145. package/src/types/index.ts +4 -4
  146. package/src/utils/dev-port.ts +176 -0
  147. package/src/utils/logger.ts +143 -0
  148. package/src/utils/logging.ts +5 -2
  149. package/src/utils/request-logger.ts +66 -0
  150. package/test/admin-routes.test.ts +114 -65
  151. package/test/api-generator.test.ts +73 -30
  152. package/test/ast-schema-editor.test.ts +5 -3
  153. package/test/auth-middleware-hono.test.ts +268 -33
  154. package/test/auth-routes.test.ts +325 -146
  155. package/test/driver-registry.test.ts +4 -2
  156. package/test/error-propagation.test.ts +226 -0
  157. package/test/errors.test.ts +12 -7
  158. package/test/jwt-security.test.ts +18 -9
  159. package/test/jwt.test.ts +26 -13
  160. package/test/middleware.test.ts +13 -8
  161. package/test/query-parser.test.ts +13 -8
  162. package/test/rate-limiter.test.ts +7 -7
  163. package/test/safe-compare.test.ts +66 -0
  164. package/test/singleton.test.ts +59 -0
  165. package/test/storage-local.test.ts +36 -43
  166. package/test/storage-registry.test.ts +38 -36
  167. package/test/storage-routes.test.ts +9 -5
  168. package/test/storage-s3.test.ts +51 -48
  169. package/test.ts +6 -0
  170. package/tsconfig.json +1 -1
  171. package/vite.config.ts +7 -5
  172. package/dist/index-BeMqpmfQ.js +0 -239
  173. package/dist/index-BeMqpmfQ.js.map +0 -1
  174. package/dist/index-bl4J3lNb.js +0 -55823
  175. package/dist/index-bl4J3lNb.js.map +0 -1
  176. package/vite.config.ts.timestamp-1775065397568-8a853255edf6e.mjs +0 -46
@@ -30,18 +30,21 @@ function mockUser(overrides: Partial<{ id: string; email: string; displayName: s
30
30
  passwordHash: "salt:hash",
31
31
  displayName: overrides.displayName ?? "Test User",
32
32
  photoUrl: overrides.photoUrl ?? null,
33
- provider: overrides.provider ?? "email",
34
- googleId: null,
35
33
  emailVerified: false,
36
34
  emailVerificationToken: null,
37
35
  emailVerificationSentAt: null,
38
36
  createdAt: new Date("2024-01-01"),
39
- updatedAt: new Date("2024-01-01"),
37
+ updatedAt: new Date("2024-01-01")
40
38
  };
41
39
  }
42
40
 
43
41
  function mockRole(id: string, isAdmin = false) {
44
- return { id, name: id.charAt(0).toUpperCase() + id.slice(1), isAdmin, defaultPermissions: null, collectionPermissions: null, config: null };
42
+ return { id,
43
+ name: id.charAt(0).toUpperCase() + id.slice(1),
44
+ isAdmin,
45
+ defaultPermissions: null,
46
+ collectionPermissions: null,
47
+ config: null };
45
48
  }
46
49
 
47
50
 
@@ -50,10 +53,14 @@ let mockAuthRepo: jest.Mocked<any>;
50
53
  function createApp(opts: { defaultRole?: string } = {}) {
51
54
  mockAuthRepo = {
52
55
  getUserByEmail: jest.fn().mockResolvedValue(null),
53
- getUserByGoogleId: jest.fn().mockResolvedValue(null),
56
+ getUserByIdentity: jest.fn().mockResolvedValue(null),
57
+ linkUserIdentity: jest.fn().mockResolvedValue(undefined),
58
+ getUserIdentities: jest.fn().mockResolvedValue([]),
54
59
  getUserById: jest.fn().mockResolvedValue(null),
55
60
  createUser: jest.fn().mockImplementation((data) =>
56
- Promise.resolve(mockUser({ email: data.email, displayName: data.displayName, passwordHash: data.passwordHash }))
61
+ Promise.resolve(mockUser({ email: data.email,
62
+ displayName: data.displayName,
63
+ passwordHash: data.passwordHash }))
57
64
  ),
58
65
  listUsers: jest.fn().mockResolvedValue([]),
59
66
  getUserRoles: jest.fn().mockResolvedValue([mockRole("editor")]),
@@ -61,7 +68,8 @@ function createApp(opts: { defaultRole?: string } = {}) {
61
68
  assignDefaultRole: jest.fn().mockResolvedValue(undefined),
62
69
  setUserRoles: jest.fn().mockResolvedValue(undefined),
63
70
  updateUser: jest.fn().mockImplementation((id, data) =>
64
- Promise.resolve(mockUser({ id, ...data }))
71
+ Promise.resolve(mockUser({ id,
72
+ ...data }))
65
73
  ),
66
74
  deleteUser: jest.fn().mockResolvedValue(undefined),
67
75
  updatePassword: jest.fn().mockResolvedValue(undefined),
@@ -70,7 +78,8 @@ function createApp(opts: { defaultRole?: string } = {}) {
70
78
  getUserByVerificationToken: jest.fn().mockResolvedValue(null),
71
79
  getUserWithRoles: jest.fn().mockImplementation(async (userId) => {
72
80
  const user = mockUser({ id: userId });
73
- return { user, roles: [mockRole("editor")] };
81
+ return { user,
82
+ roles: [mockRole("editor")] };
74
83
  }),
75
84
  createRefreshToken: jest.fn().mockResolvedValue(undefined),
76
85
  findRefreshTokenByHash: jest.fn().mockResolvedValue(null),
@@ -84,19 +93,30 @@ function createApp(opts: { defaultRole?: string } = {}) {
84
93
  deleteExpiredPasswordResetTokens: jest.fn().mockResolvedValue(undefined),
85
94
  listRoles: jest.fn().mockResolvedValue([]),
86
95
  getRoleById: jest.fn().mockResolvedValue(null),
87
- createRole: jest.fn().mockImplementation(r => Promise.resolve({ id: r.id, name: r.name, isAdmin: r.isAdmin || false, defaultPermissions: null, collectionPermissions: null, config: null })),
88
- updateRole: jest.fn().mockImplementation((id, r) => Promise.resolve({ id, name: r.name, isAdmin: r.isAdmin || false, defaultPermissions: null, collectionPermissions: null, config: null })),
96
+ createRole: jest.fn().mockImplementation(r => Promise.resolve({ id: r.id,
97
+ name: r.name,
98
+ isAdmin: r.isAdmin || false,
99
+ defaultPermissions: null,
100
+ collectionPermissions: null,
101
+ config: null })),
102
+ updateRole: jest.fn().mockImplementation((id, r) => Promise.resolve({ id,
103
+ name: r.name,
104
+ isAdmin: r.isAdmin || false,
105
+ defaultPermissions: null,
106
+ collectionPermissions: null,
107
+ config: null })),
89
108
  deleteRole: jest.fn().mockResolvedValue(undefined)
90
109
  } as unknown as jest.Mocked<AuthRepository>;
91
-
110
+
92
111
 
93
112
  // Password mocks
94
- (validatePasswordStrength as jest.Mock).mockReturnValue({ valid: true, errors: [] });
113
+ (validatePasswordStrength as jest.Mock).mockReturnValue({ valid: true,
114
+ errors: [] });
95
115
  (hashPassword as jest.Mock).mockResolvedValue("hashed-pw");
96
116
 
97
117
  const config: AuthModuleConfig = {
98
118
  authRepo: mockAuthRepo,
99
- defaultRole: opts.defaultRole,
119
+ defaultRole: opts.defaultRole
100
120
  };
101
121
 
102
122
  const app = new Hono<HonoEnv>();
@@ -117,7 +137,7 @@ function json(body: Record<string, unknown>) {
117
137
  return {
118
138
  method: "POST" as const,
119
139
  headers: { "Content-Type": "application/json" },
120
- body: JSON.stringify(body),
140
+ body: JSON.stringify(body)
121
141
  };
122
142
  }
123
143
 
@@ -127,7 +147,8 @@ function json(body: Record<string, unknown>) {
127
147
 
128
148
  describe("Admin Routes (Integration)", () => {
129
149
  beforeAll(() => {
130
- configureJwt({ secret: TEST_SECRET, accessExpiresIn: "1h" });
150
+ configureJwt({ secret: TEST_SECRET,
151
+ accessExpiresIn: "1h" });
131
152
  });
132
153
 
133
154
  beforeEach(() => {
@@ -145,7 +166,7 @@ describe("Admin Routes (Integration)", () => {
145
166
  it("returns 403 for non-admin users on admin-only endpoints", async () => {
146
167
  const app = createApp();
147
168
  const res = await app.request("/admin/users", {
148
- headers: { ...editorAuth() },
169
+ headers: { ...editorAuth() }
149
170
  });
150
171
  expect(res.status).toBe(403);
151
172
  });
@@ -153,7 +174,7 @@ describe("Admin Routes (Integration)", () => {
153
174
  it("allows admin users through", async () => {
154
175
  const app = createApp();
155
176
  const res = await app.request("/admin/users", {
156
- headers: { ...adminAuth() },
177
+ headers: { ...adminAuth() }
157
178
  });
158
179
  expect(res.status).toBe(200);
159
180
  });
@@ -161,7 +182,7 @@ describe("Admin Routes (Integration)", () => {
161
182
  it("allows schema-admin users through", async () => {
162
183
  const app = createApp();
163
184
  const res = await app.request("/admin/users", {
164
- headers: { Authorization: `Bearer ${generateAccessToken("sa-1", ["schema-admin"])}` },
185
+ headers: { Authorization: `Bearer ${generateAccessToken("sa-1", ["schema-admin"])}` }
165
186
  });
166
187
  expect(res.status).toBe(200);
167
188
  });
@@ -176,7 +197,7 @@ describe("Admin Routes (Integration)", () => {
176
197
 
177
198
  const res = await app.request("/admin/bootstrap", {
178
199
  method: "POST",
179
- headers: { ...adminAuth("user-1") },
200
+ headers: { ...adminAuth("user-1") }
180
201
  });
181
202
  expect(res.status).toBe(200);
182
203
  const body = await res.json() as any;
@@ -192,7 +213,7 @@ describe("Admin Routes (Integration)", () => {
192
213
 
193
214
  const res = await app.request("/admin/bootstrap", {
194
215
  method: "POST",
195
- headers: { ...adminAuth("user-1") },
216
+ headers: { ...adminAuth("user-1") }
196
217
  });
197
218
  expect(res.status).toBe(403);
198
219
  const body = await res.json() as any;
@@ -206,8 +227,10 @@ describe("Admin Routes (Integration)", () => {
206
227
  it("returns list of users with roles", async () => {
207
228
  const app = createApp();
208
229
  mockAuthRepo.listUsers.mockResolvedValueOnce([
209
- mockUser({ id: "u1", email: "a@test.com" }),
210
- mockUser({ id: "u2", email: "b@test.com" }),
230
+ mockUser({ id: "u1",
231
+ email: "a@test.com" }),
232
+ mockUser({ id: "u2",
233
+ email: "b@test.com" })
211
234
  ]);
212
235
  mockAuthRepo.getUserRoleIds
213
236
  .mockResolvedValueOnce(["admin"])
@@ -227,7 +250,7 @@ describe("Admin Routes (Integration)", () => {
227
250
  const app = createApp();
228
251
  mockAuthRepo.getUserWithRoles.mockResolvedValueOnce({
229
252
  user: mockUser({ id: "u1" }),
230
- roles: [mockRole("editor"), mockRole("viewer")],
253
+ roles: [mockRole("editor"), mockRole("viewer")]
231
254
  });
232
255
 
233
256
  const res = await app.request("/admin/users/u1", { headers: { ...adminAuth() } });
@@ -251,14 +274,18 @@ describe("Admin Routes (Integration)", () => {
251
274
  const app = createApp();
252
275
 
253
276
  const res = await app.request("/admin/users", {
254
- ...json({ email: "new@test.com", displayName: "New", password: "StrongPass1", roles: ["editor"] }),
255
- headers: { ...json({}).headers, ...adminAuth() },
277
+ ...json({ email: "new@test.com",
278
+ displayName: "New",
279
+ password: "StrongPass1",
280
+ roles: ["editor"] }),
281
+ headers: { ...json({}).headers,
282
+ ...adminAuth() }
256
283
  });
257
284
  expect(res.status).toBe(201);
258
285
  const body = await res.json() as any;
259
286
  expect(body.user.email).toBe("new@test.com");
260
287
  expect(mockAuthRepo.createUser).toHaveBeenCalledWith(expect.objectContaining({
261
- email: "new@test.com",
288
+ email: "new@test.com"
262
289
  }));
263
290
  });
264
291
 
@@ -266,8 +293,10 @@ describe("Admin Routes (Integration)", () => {
266
293
  const app = createApp();
267
294
 
268
295
  await app.request("/admin/users", {
269
- ...json({ email: "pw@test.com", password: "StrongPass1" }),
270
- headers: { ...json({}).headers, ...adminAuth() },
296
+ ...json({ email: "pw@test.com",
297
+ password: "StrongPass1" }),
298
+ headers: { ...json({}).headers,
299
+ ...adminAuth() }
271
300
  });
272
301
  expect(hashPassword).toHaveBeenCalledWith("StrongPass1");
273
302
  });
@@ -277,7 +306,8 @@ describe("Admin Routes (Integration)", () => {
277
306
 
278
307
  const res = await app.request("/admin/users", {
279
308
  ...json({ displayName: "No Email" }),
280
- headers: { ...json({}).headers, ...adminAuth() },
309
+ headers: { ...json({}).headers,
310
+ ...adminAuth() }
281
311
  });
282
312
  expect(res.status).toBe(400);
283
313
  });
@@ -288,7 +318,8 @@ describe("Admin Routes (Integration)", () => {
288
318
 
289
319
  const res = await app.request("/admin/users", {
290
320
  ...json({ email: "existing@test.com" }),
291
- headers: { ...json({}).headers, ...adminAuth() },
321
+ headers: { ...json({}).headers,
322
+ ...adminAuth() }
292
323
  });
293
324
  expect(res.status).toBe(409);
294
325
  const body = await res.json() as any;
@@ -297,11 +328,14 @@ describe("Admin Routes (Integration)", () => {
297
328
 
298
329
  it("returns 400 for weak password", async () => {
299
330
  const app = createApp();
300
- (validatePasswordStrength as jest.Mock).mockReturnValueOnce({ valid: false, errors: ["Too short"] });
331
+ (validatePasswordStrength as jest.Mock).mockReturnValueOnce({ valid: false,
332
+ errors: ["Too short"] });
301
333
 
302
334
  const res = await app.request("/admin/users", {
303
- ...json({ email: "weak@test.com", password: "weak" }),
304
- headers: { ...json({}).headers, ...adminAuth() },
335
+ ...json({ email: "weak@test.com",
336
+ password: "weak" }),
337
+ headers: { ...json({}).headers,
338
+ ...adminAuth() }
305
339
  });
306
340
  expect(res.status).toBe(400);
307
341
  const body = await res.json() as any;
@@ -313,7 +347,8 @@ describe("Admin Routes (Integration)", () => {
313
347
 
314
348
  await app.request("/admin/users", {
315
349
  ...json({ email: "norole@test.com" }),
316
- headers: { ...json({}).headers, ...adminAuth() },
350
+ headers: { ...json({}).headers,
351
+ ...adminAuth() }
317
352
  });
318
353
  expect(mockAuthRepo.assignDefaultRole).toHaveBeenCalledWith(expect.any(String), "editor");
319
354
  });
@@ -323,7 +358,8 @@ describe("Admin Routes (Integration)", () => {
323
358
 
324
359
  await app.request("/admin/users", {
325
360
  ...json({ email: "nodefault@test.com" }),
326
- headers: { ...json({}).headers, ...adminAuth() },
361
+ headers: { ...json({}).headers,
362
+ ...adminAuth() }
327
363
  });
328
364
  expect(mockAuthRepo.assignDefaultRole).not.toHaveBeenCalled();
329
365
  });
@@ -332,8 +368,10 @@ describe("Admin Routes (Integration)", () => {
332
368
  const app = createApp();
333
369
 
334
370
  await app.request("/admin/users", {
335
- ...json({ email: "withroles@test.com", roles: ["admin", "editor"] }),
336
- headers: { ...json({}).headers, ...adminAuth() },
371
+ ...json({ email: "withroles@test.com",
372
+ roles: ["admin", "editor"] }),
373
+ headers: { ...json({}).headers,
374
+ ...adminAuth() }
337
375
  });
338
376
  expect(mockAuthRepo.setUserRoles).toHaveBeenCalledWith(expect.any(String), ["admin", "editor"]);
339
377
  });
@@ -344,14 +382,16 @@ describe("Admin Routes (Integration)", () => {
344
382
  const app = createApp();
345
383
  mockAuthRepo.getUserById.mockResolvedValueOnce(mockUser({ id: "u1" }));
346
384
  mockAuthRepo.getUserWithRoles.mockResolvedValueOnce({
347
- user: mockUser({ id: "u1", displayName: "Updated" }),
348
- roles: [mockRole("editor")],
385
+ user: mockUser({ id: "u1",
386
+ displayName: "Updated" }),
387
+ roles: [mockRole("editor")]
349
388
  });
350
389
 
351
390
  const res = await app.request("/admin/users/u1", {
352
391
  method: "PUT",
353
- headers: { "Content-Type": "application/json", ...adminAuth() },
354
- body: JSON.stringify({ displayName: "Updated" }),
392
+ headers: { "Content-Type": "application/json",
393
+ ...adminAuth() },
394
+ body: JSON.stringify({ displayName: "Updated" })
355
395
  });
356
396
  expect(res.status).toBe(200);
357
397
  const body = await res.json() as any;
@@ -363,13 +403,14 @@ describe("Admin Routes (Integration)", () => {
363
403
  mockAuthRepo.getUserById.mockResolvedValueOnce(mockUser({ id: "u1" }));
364
404
  mockAuthRepo.getUserWithRoles.mockResolvedValueOnce({
365
405
  user: mockUser({ id: "u1" }),
366
- roles: [mockRole("admin")],
406
+ roles: [mockRole("admin")]
367
407
  });
368
408
 
369
409
  await app.request("/admin/users/u1", {
370
410
  method: "PUT",
371
- headers: { "Content-Type": "application/json", ...adminAuth() },
372
- body: JSON.stringify({ roles: ["admin"] }),
411
+ headers: { "Content-Type": "application/json",
412
+ ...adminAuth() },
413
+ body: JSON.stringify({ roles: ["admin"] })
373
414
  });
374
415
  expect(mockAuthRepo.setUserRoles).toHaveBeenCalledWith("u1", ["admin"]);
375
416
  });
@@ -380,8 +421,9 @@ describe("Admin Routes (Integration)", () => {
380
421
 
381
422
  const res = await app.request("/admin/users/missing", {
382
423
  method: "PUT",
383
- headers: { "Content-Type": "application/json", ...adminAuth() },
384
- body: JSON.stringify({ displayName: "Updated" }),
424
+ headers: { "Content-Type": "application/json",
425
+ ...adminAuth() },
426
+ body: JSON.stringify({ displayName: "Updated" })
385
427
  });
386
428
  expect(res.status).toBe(404);
387
429
  });
@@ -394,7 +436,7 @@ describe("Admin Routes (Integration)", () => {
394
436
 
395
437
  const res = await app.request("/admin/users/u1", {
396
438
  method: "DELETE",
397
- headers: { ...adminAuth("admin-1") },
439
+ headers: { ...adminAuth("admin-1") }
398
440
  });
399
441
  expect(res.status).toBe(200);
400
442
  expect(mockAuthRepo.deleteUser).toHaveBeenCalledWith("u1");
@@ -405,7 +447,7 @@ describe("Admin Routes (Integration)", () => {
405
447
 
406
448
  const res = await app.request("/admin/users/admin-1", {
407
449
  method: "DELETE",
408
- headers: { ...adminAuth("admin-1") },
450
+ headers: { ...adminAuth("admin-1") }
409
451
  });
410
452
  expect(res.status).toBe(400);
411
453
  const body = await res.json() as any;
@@ -418,7 +460,7 @@ describe("Admin Routes (Integration)", () => {
418
460
 
419
461
  const res = await app.request("/admin/users/missing", {
420
462
  method: "DELETE",
421
- headers: { ...adminAuth() },
463
+ headers: { ...adminAuth() }
422
464
  });
423
465
  expect(res.status).toBe(404);
424
466
  });
@@ -433,7 +475,7 @@ describe("Admin Routes (Integration)", () => {
433
475
  mockAuthRepo.listRoles.mockResolvedValueOnce([
434
476
  mockRole("admin", true),
435
477
  mockRole("editor"),
436
- mockRole("viewer"),
478
+ mockRole("viewer")
437
479
  ]);
438
480
 
439
481
  const res = await app.request("/admin/roles", { headers: { ...adminAuth() } });
@@ -470,8 +512,10 @@ describe("Admin Routes (Integration)", () => {
470
512
  const app = createApp();
471
513
 
472
514
  const res = await app.request("/admin/roles", {
473
- ...json({ id: "custom", name: "Custom Role" }),
474
- headers: { ...json({}).headers, ...adminAuth() },
515
+ ...json({ id: "custom",
516
+ name: "Custom Role" }),
517
+ headers: { ...json({}).headers,
518
+ ...adminAuth() }
475
519
  });
476
520
  expect(res.status).toBe(201);
477
521
  const body = await res.json() as any;
@@ -483,7 +527,8 @@ describe("Admin Routes (Integration)", () => {
483
527
 
484
528
  const res = await app.request("/admin/roles", {
485
529
  ...json({ id: "nope" }),
486
- headers: { ...json({}).headers, ...adminAuth() },
530
+ headers: { ...json({}).headers,
531
+ ...adminAuth() }
487
532
  });
488
533
  expect(res.status).toBe(400);
489
534
  });
@@ -493,8 +538,10 @@ describe("Admin Routes (Integration)", () => {
493
538
  mockAuthRepo.getRoleById.mockResolvedValueOnce(mockRole("custom"));
494
539
 
495
540
  const res = await app.request("/admin/roles", {
496
- ...json({ id: "custom", name: "Dup" }),
497
- headers: { ...json({}).headers, ...adminAuth() },
541
+ ...json({ id: "custom",
542
+ name: "Dup" }),
543
+ headers: { ...json({}).headers,
544
+ ...adminAuth() }
498
545
  });
499
546
  expect(res.status).toBe(409);
500
547
  const body = await res.json() as any;
@@ -509,12 +556,13 @@ describe("Admin Routes (Integration)", () => {
509
556
 
510
557
  const res = await app.request("/admin/roles/editor", {
511
558
  method: "PUT",
512
- headers: { "Content-Type": "application/json", ...adminAuth() },
513
- body: JSON.stringify({ name: "Super Editor" }),
559
+ headers: { "Content-Type": "application/json",
560
+ ...adminAuth() },
561
+ body: JSON.stringify({ name: "Super Editor" })
514
562
  });
515
563
  expect(res.status).toBe(200);
516
564
  expect(mockAuthRepo.updateRole).toHaveBeenCalledWith("editor", expect.objectContaining({
517
- name: "Super Editor",
565
+ name: "Super Editor"
518
566
  }));
519
567
  });
520
568
 
@@ -524,8 +572,9 @@ describe("Admin Routes (Integration)", () => {
524
572
 
525
573
  const res = await app.request("/admin/roles/missing", {
526
574
  method: "PUT",
527
- headers: { "Content-Type": "application/json", ...adminAuth() },
528
- body: JSON.stringify({ name: "Nope" }),
575
+ headers: { "Content-Type": "application/json",
576
+ ...adminAuth() },
577
+ body: JSON.stringify({ name: "Nope" })
529
578
  });
530
579
  expect(res.status).toBe(404);
531
580
  });
@@ -538,7 +587,7 @@ describe("Admin Routes (Integration)", () => {
538
587
 
539
588
  const res = await app.request("/admin/roles/custom", {
540
589
  method: "DELETE",
541
- headers: { ...adminAuth() },
590
+ headers: { ...adminAuth() }
542
591
  });
543
592
  expect(res.status).toBe(200);
544
593
  expect(mockAuthRepo.deleteRole).toHaveBeenCalledWith("custom");
@@ -549,7 +598,7 @@ describe("Admin Routes (Integration)", () => {
549
598
 
550
599
  const res = await app.request("/admin/roles/admin", {
551
600
  method: "DELETE",
552
- headers: { ...adminAuth() },
601
+ headers: { ...adminAuth() }
553
602
  });
554
603
  expect(res.status).toBe(400);
555
604
  const body = await res.json() as any;
@@ -561,7 +610,7 @@ describe("Admin Routes (Integration)", () => {
561
610
 
562
611
  const res = await app.request("/admin/roles/editor", {
563
612
  method: "DELETE",
564
- headers: { ...adminAuth() },
613
+ headers: { ...adminAuth() }
565
614
  });
566
615
  expect(res.status).toBe(400);
567
616
  });
@@ -571,7 +620,7 @@ describe("Admin Routes (Integration)", () => {
571
620
 
572
621
  const res = await app.request("/admin/roles/viewer", {
573
622
  method: "DELETE",
574
- headers: { ...adminAuth() },
623
+ headers: { ...adminAuth() }
575
624
  });
576
625
  expect(res.status).toBe(400);
577
626
  });
@@ -582,7 +631,7 @@ describe("Admin Routes (Integration)", () => {
582
631
 
583
632
  const res = await app.request("/admin/roles/ghost", {
584
633
  method: "DELETE",
585
- headers: { ...adminAuth() },
634
+ headers: { ...adminAuth() }
586
635
  });
587
636
  expect(res.status).toBe(404);
588
637
  });