@friggframework/core 2.0.0--canary.522.cbd3d5a.0 → 2.0.0--canary.517.35ee143.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.
Files changed (225) hide show
  1. package/CHANGELOG.md +67 -66
  2. package/CLAUDE.md +124 -148
  3. package/README.md +130 -165
  4. package/admin-scripts/index.js +16 -30
  5. package/admin-scripts/repositories/{admin-api-key-repository-documentdb.js → admin-process-repository-documentdb.js} +5 -5
  6. package/admin-scripts/repositories/{admin-api-key-repository-factory.js → admin-process-repository-factory.js} +15 -19
  7. package/admin-scripts/repositories/admin-process-repository-interface.js +150 -0
  8. package/admin-scripts/repositories/admin-process-repository-mongo.js +213 -0
  9. package/admin-scripts/repositories/admin-process-repository-postgres.js +251 -0
  10. package/admin-scripts/repositories/script-schedule-repository-factory.js +2 -6
  11. package/admin-scripts/repositories/script-schedule-repository-interface.js +14 -36
  12. package/admin-scripts/repositories/script-schedule-repository-mongo.js +13 -25
  13. package/admin-scripts/repositories/script-schedule-repository-postgres.js +13 -25
  14. package/application/commands/admin-script-commands.js +102 -266
  15. package/application/commands/integration-commands.js +6 -12
  16. package/application/index.js +3 -1
  17. package/assertions/get.js +4 -1
  18. package/associations/association.js +57 -59
  19. package/associations/model.js +41 -41
  20. package/core/CLAUDE.md +156 -222
  21. package/core/Worker.js +1 -5
  22. package/credential/repositories/credential-repository-documentdb.js +1 -71
  23. package/credential/repositories/credential-repository-interface.js +2 -8
  24. package/credential/repositories/credential-repository-mongo.js +4 -45
  25. package/credential/repositories/credential-repository-postgres.js +3 -44
  26. package/credential/repositories/credential-repository.js +4 -6
  27. package/credential/use-cases/get-credential-for-user.js +3 -21
  28. package/credential/use-cases/update-authentication-status.js +2 -5
  29. package/database/MONGODB_TRANSACTION_FIX.md +52 -72
  30. package/database/adapters/lambda-invoker.js +7 -8
  31. package/database/config.js +13 -15
  32. package/database/documentdb-encryption-service.js +13 -29
  33. package/database/documentdb-utils.js +12 -21
  34. package/database/encryption/README.md +36 -53
  35. package/database/encryption/encryption-schema-registry.js +9 -21
  36. package/database/encryption/field-encryption-service.js +4 -15
  37. package/database/encryption/logger.js +2 -3
  38. package/database/encryption/prisma-encryption-extension.js +8 -5
  39. package/database/index.js +2 -4
  40. package/database/models/IndividualUser.js +15 -15
  41. package/database/models/OrganizationUser.js +4 -6
  42. package/database/models/UserModel.js +2 -2
  43. package/database/models/WebsocketConnection.js +1 -4
  44. package/database/mongoose.js +2 -2
  45. package/database/prisma.js +14 -22
  46. package/database/repositories/health-check-repository-documentdb.js +7 -22
  47. package/database/repositories/health-check-repository-factory.js +3 -9
  48. package/database/repositories/health-check-repository-interface.js +5 -15
  49. package/database/repositories/health-check-repository-mongodb.js +6 -9
  50. package/database/repositories/health-check-repository-postgres.js +1 -1
  51. package/database/repositories/migration-status-repository-s3.js +5 -10
  52. package/database/use-cases/check-database-health-use-case.js +2 -3
  53. package/database/use-cases/check-database-state-use-case.js +7 -9
  54. package/database/use-cases/get-database-state-via-worker-use-case.js +12 -15
  55. package/database/use-cases/get-migration-status-use-case.js +2 -4
  56. package/database/use-cases/run-database-migration-use-case.js +9 -41
  57. package/database/use-cases/test-encryption-use-case.js +5 -4
  58. package/database/use-cases/trigger-database-migration-use-case.js +8 -9
  59. package/database/utils/mongodb-collection-utils.js +3 -11
  60. package/database/utils/mongodb-schema-init.js +4 -10
  61. package/database/utils/prisma-runner.js +74 -144
  62. package/database/utils/prisma-schema-parser.js +2 -2
  63. package/docs/PROCESS_MANAGEMENT_QUEUE_SPEC.md +80 -135
  64. package/encrypt/Cryptor.js +2 -8
  65. package/errors/fetch-error.js +1 -1
  66. package/generated/prisma-mongodb/edge.js +16 -59
  67. package/generated/prisma-mongodb/index-browser.js +12 -62
  68. package/generated/prisma-mongodb/index.d.ts +4850 -8136
  69. package/generated/prisma-mongodb/index.js +16 -59
  70. package/generated/prisma-mongodb/package.json +1 -1
  71. package/generated/prisma-mongodb/schema.prisma +33 -75
  72. package/generated/prisma-mongodb/wasm.js +16 -59
  73. package/generated/prisma-postgresql/edge.js +15 -59
  74. package/generated/prisma-postgresql/index-browser.js +11 -62
  75. package/generated/prisma-postgresql/index.d.ts +5963 -8930
  76. package/generated/prisma-postgresql/index.js +15 -59
  77. package/generated/prisma-postgresql/package.json +1 -1
  78. package/generated/prisma-postgresql/schema.prisma +33 -73
  79. package/generated/prisma-postgresql/wasm.js +15 -59
  80. package/handlers/WEBHOOKS.md +81 -104
  81. package/handlers/app-definition-loader.js +1 -1
  82. package/handlers/app-handler-helpers.js +2 -14
  83. package/handlers/backend-utils.js +1 -0
  84. package/handlers/database-migration-handler.js +45 -64
  85. package/handlers/middleware/admin-auth.js +53 -0
  86. package/handlers/routers/HEALTHCHECK.md +135 -170
  87. package/handlers/routers/auth.js +2 -23
  88. package/handlers/routers/db-migration.handler.js +3 -2
  89. package/handlers/routers/db-migration.js +33 -69
  90. package/handlers/routers/health.js +8 -23
  91. package/handlers/routers/integration-defined-routers.js +4 -4
  92. package/handlers/routers/integration-webhook-routers.js +7 -17
  93. package/handlers/routers/websocket.js +3 -9
  94. package/handlers/use-cases/check-integrations-health-use-case.js +6 -13
  95. package/handlers/workers/db-migration.js +26 -54
  96. package/index.js +9 -5
  97. package/integrations/WEBHOOK-QUICKSTART.md +14 -21
  98. package/integrations/index.js +0 -4
  99. package/integrations/integration-base.js +6 -9
  100. package/integrations/integration-router.js +146 -1817
  101. package/integrations/options.js +20 -47
  102. package/integrations/repositories/integration-repository-documentdb.js +24 -53
  103. package/integrations/repositories/integration-repository-factory.js +2 -6
  104. package/integrations/repositories/integration-repository-interface.js +9 -27
  105. package/integrations/repositories/integration-repository-postgres.js +3 -3
  106. package/integrations/repositories/process-repository-factory.js +1 -0
  107. package/integrations/repositories/process-repository-interface.js +5 -9
  108. package/integrations/repositories/process-repository-mongo.js +3 -7
  109. package/integrations/repositories/process-repository-postgres.js +2 -2
  110. package/integrations/tests/doubles/config-capturing-integration.js +8 -9
  111. package/integrations/tests/doubles/dummy-integration-class.js +8 -81
  112. package/integrations/tests/doubles/test-integration-repository.js +11 -51
  113. package/integrations/use-cases/create-integration.js +32 -36
  114. package/integrations/use-cases/create-process.js +9 -20
  115. package/integrations/use-cases/delete-integration-for-user.js +4 -5
  116. package/integrations/use-cases/get-integration-for-user.js +10 -25
  117. package/integrations/use-cases/get-integration-instance-by-definition.js +7 -13
  118. package/integrations/use-cases/get-integrations-for-user.js +1 -4
  119. package/integrations/use-cases/get-possible-integrations.js +1 -1
  120. package/integrations/use-cases/get-process.js +6 -5
  121. package/integrations/use-cases/index.js +1 -3
  122. package/integrations/use-cases/load-integration-context.js +5 -1
  123. package/integrations/use-cases/update-process-state.js +8 -10
  124. package/integrations/utils/map-integration-dto.js +3 -9
  125. package/jest-setup.js +1 -1
  126. package/jest-teardown.js +1 -1
  127. package/lambda/TimeoutCatcher.js +30 -32
  128. package/lambda/index.js +1 -1
  129. package/logs/index.js +3 -3
  130. package/modules/module.js +1 -3
  131. package/modules/repositories/module-repository-documentdb.js +48 -114
  132. package/modules/repositories/module-repository-interface.js +0 -13
  133. package/modules/repositories/module-repository-mongo.js +6 -46
  134. package/modules/repositories/module-repository-postgres.js +6 -48
  135. package/modules/repositories/module-repository.js +1 -34
  136. package/modules/requester/api-key.js +2 -0
  137. package/modules/requester/basic.js +1 -0
  138. package/modules/requester/oauth-2.js +2 -3
  139. package/modules/test/mock-api/definition.js +10 -15
  140. package/modules/test/mock-api/mocks/hubspot.js +36 -36
  141. package/modules/tests/doubles/test-module-factory.js +4 -10
  142. package/modules/tests/doubles/test-module-repository.js +1 -1
  143. package/modules/use-cases/get-entities-for-user.js +1 -1
  144. package/modules/use-cases/get-entity-options-by-id.js +6 -8
  145. package/modules/use-cases/get-module.js +9 -12
  146. package/modules/use-cases/process-authorization-callback.js +6 -12
  147. package/modules/use-cases/refresh-entity-options.js +6 -8
  148. package/modules/use-cases/test-module-auth.js +6 -8
  149. package/modules/utils/map-module-dto.js +2 -2
  150. package/package.json +5 -7
  151. package/prisma-mongodb/schema.prisma +33 -75
  152. package/prisma-postgresql/schema.prisma +33 -73
  153. package/queues/queuer-util.js +1 -5
  154. package/syncs/model.js +51 -51
  155. package/syncs/repositories/sync-repository-documentdb.js +19 -39
  156. package/syncs/repositories/sync-repository-interface.js +2 -6
  157. package/syncs/repositories/sync-repository-postgres.js +13 -19
  158. package/syncs/sync.js +100 -104
  159. package/token/repositories/token-repository-factory.js +3 -1
  160. package/types/assertions/index.d.ts +72 -72
  161. package/types/associations/index.d.ts +57 -57
  162. package/types/core/index.d.ts +53 -59
  163. package/types/database/index.d.ts +2 -2
  164. package/types/encrypt/index.d.ts +3 -3
  165. package/types/errors/index.d.ts +54 -61
  166. package/types/eslint-config/index.d.ts +40 -40
  167. package/types/integrations/index.d.ts +183 -185
  168. package/types/lambda/index.d.ts +26 -26
  169. package/types/logs/index.d.ts +4 -4
  170. package/types/module-plugin/index.d.ts +237 -239
  171. package/types/prettier-config/index.d.ts +5 -5
  172. package/types/syncs/index.d.ts +108 -102
  173. package/types/test-environment/index.d.ts +14 -14
  174. package/types/tsconfig.json +93 -95
  175. package/user/tests/doubles/test-user-repository.js +2 -5
  176. package/user/use-cases/authenticate-user.js +4 -2
  177. package/user/use-cases/authenticate-with-shared-secret.js +1 -1
  178. package/user/use-cases/create-individual-user.js +7 -8
  179. package/user/use-cases/create-organization-user.js +1 -1
  180. package/user/use-cases/create-token-for-user-id.js +1 -1
  181. package/user/use-cases/get-user-from-adopter-jwt.js +2 -0
  182. package/user/use-cases/get-user-from-bearer-token.js +3 -7
  183. package/user/use-cases/get-user-from-x-frigg-headers.js +11 -14
  184. package/user/use-cases/login-user.js +8 -8
  185. package/user/user.js +4 -18
  186. package/utils/backend-path.js +2 -2
  187. package/utils/index.js +1 -4
  188. package/websocket/repositories/websocket-connection-repository-documentdb.js +8 -21
  189. package/websocket/repositories/websocket-connection-repository-mongo.js +4 -8
  190. package/websocket/repositories/websocket-connection-repository-postgres.js +4 -8
  191. package/websocket/repositories/websocket-connection-repository.js +4 -8
  192. package/admin-scripts/repositories/admin-api-key-repository-interface.js +0 -121
  193. package/admin-scripts/repositories/admin-api-key-repository-mongo.js +0 -155
  194. package/admin-scripts/repositories/admin-api-key-repository-postgres.js +0 -189
  195. package/admin-scripts/repositories/script-execution-repository-documentdb.js +0 -21
  196. package/admin-scripts/repositories/script-execution-repository-factory.js +0 -55
  197. package/admin-scripts/repositories/script-execution-repository-interface.js +0 -193
  198. package/admin-scripts/repositories/script-execution-repository-mongo.js +0 -278
  199. package/admin-scripts/repositories/script-execution-repository-postgres.js +0 -320
  200. package/credential/credential-router.js +0 -262
  201. package/credential/use-cases/delete-credential-for-user.js +0 -50
  202. package/credential/use-cases/list-credentials-for-user.js +0 -31
  203. package/credential/use-cases/reauthorize-credential.js +0 -103
  204. package/handlers/routers/admin.js +0 -450
  205. package/handlers/routers/docs.js +0 -180
  206. package/handlers/routers/middleware/loadUser.js +0 -39
  207. package/handlers/routers/middleware/requireAdmin.js +0 -41
  208. package/handlers/routers/middleware/requireLoggedInUser.js +0 -19
  209. package/integrations/use-cases/execute-proxy-request.js +0 -564
  210. package/modules/domain/entities/AuthorizationSession.js +0 -131
  211. package/modules/domain/entities/index.js +0 -10
  212. package/modules/repositories/authorization-session-repository-factory.js +0 -55
  213. package/modules/repositories/authorization-session-repository-interface.js +0 -75
  214. package/modules/repositories/authorization-session-repository-mongo.js +0 -169
  215. package/modules/repositories/authorization-session-repository-postgres.js +0 -170
  216. package/modules/use-cases/delete-module-entity.js +0 -23
  217. package/modules/use-cases/get-authorization-requirements.js +0 -110
  218. package/modules/use-cases/get-module-entity-by-id.js +0 -16
  219. package/modules/use-cases/process-authorization-step.js +0 -160
  220. package/modules/use-cases/start-authorization-session.js +0 -86
  221. package/modules/use-cases/update-module-entity.js +0 -27
  222. package/openapi/openapi-spec-generator.js +0 -370
  223. package/openapi/openapi-v1.yaml +0 -1360
  224. package/openapi/openapi-v2.yaml +0 -1535
  225. package/user/use-cases/delete-user.js +0 -47
@@ -76,11 +76,10 @@ class GetUserFromXFriggHeaders {
76
76
  }
77
77
 
78
78
  // Auto-link the users
79
- individualUserData =
80
- await this.userRepository.linkIndividualToOrganization(
81
- individualUserData.id,
82
- organizationUserData.id
83
- );
79
+ individualUserData = await this.userRepository.linkIndividualToOrganization(
80
+ individualUserData.id,
81
+ organizationUserData.id
82
+ );
84
83
  }
85
84
  }
86
85
 
@@ -90,13 +89,12 @@ class GetUserFromXFriggHeaders {
90
89
  appUserId &&
91
90
  this.userConfig.individualUserRequired !== false
92
91
  ) {
93
- individualUserData = await this.userRepository.createIndividualUser(
94
- {
92
+ individualUserData =
93
+ await this.userRepository.createIndividualUser({
95
94
  appUserId,
96
95
  username: `app-user-${appUserId}`,
97
96
  email: `${appUserId}@app.local`,
98
- }
99
- );
97
+ });
100
98
  }
101
99
 
102
100
  if (
@@ -111,11 +109,10 @@ class GetUserFromXFriggHeaders {
111
109
 
112
110
  // Link individual user to newly created org user if individual exists
113
111
  if (individualUserData && organizationUserData) {
114
- individualUserData =
115
- await this.userRepository.linkIndividualToOrganization(
116
- individualUserData.id,
117
- organizationUserData.id
118
- );
112
+ individualUserData = await this.userRepository.linkIndividualToOrganization(
113
+ individualUserData.id,
114
+ organizationUserData.id
115
+ );
119
116
  }
120
117
  }
121
118
 
@@ -1,5 +1,7 @@
1
1
  const Boom = require('@hapi/boom');
2
- const { RequiredPropertyError } = require('../../errors');
2
+ const {
3
+ RequiredPropertyError,
4
+ } = require('../../errors');
3
5
  const { User } = require('../user');
4
6
 
5
7
  /**
@@ -91,11 +93,11 @@ class LoginUser {
91
93
  }
92
94
  }
93
95
 
96
+
94
97
  if (this.userConfig.organizationUserRequired) {
98
+
95
99
  const organizationUserData =
96
- await this.userRepository.findOrganizationUserByAppOrgId(
97
- appOrgId
98
- );
100
+ await this.userRepository.findOrganizationUserByAppOrgId(appOrgId);
99
101
 
100
102
  if (!organizationUserData) {
101
103
  throw Boom.unauthorized(`org user ${appOrgId} not found`);
@@ -113,10 +115,8 @@ class LoginUser {
113
115
  return organizationUser;
114
116
  }
115
117
 
116
- throw new Error(
117
- 'User configuration must require either individualUserRequired or organizationUserRequired'
118
- );
118
+ throw new Error('User configuration must require either individualUserRequired or organizationUserRequired');
119
119
  }
120
120
  }
121
121
 
122
- module.exports = { LoginUser };
122
+ module.exports = { LoginUser };
package/user/user.js CHANGED
@@ -14,14 +14,7 @@ class User {
14
14
  * @param {boolean} [individualUserRequired=true] - Whether the user is required to have an individual user.
15
15
  * @param {boolean} [organizationUserRequired=false] - Whether the user is required to have an organization user.
16
16
  */
17
- constructor(
18
- individualUser = null,
19
- organizationUser = null,
20
- usePassword = false,
21
- primary = 'individual',
22
- individualUserRequired = true,
23
- organizationUserRequired = false
24
- ) {
17
+ constructor(individualUser = null, organizationUser = null, usePassword = false, primary = 'individual', individualUserRequired = true, organizationUserRequired = false) {
25
18
  this.individualUser = individualUser;
26
19
  this.organizationUser = organizationUser;
27
20
  this.usePassword = usePassword;
@@ -116,19 +109,12 @@ class User {
116
109
  }
117
110
 
118
111
  // When primary is 'organization', also check linked individual user
119
- if (
120
- this.config.primary === 'organization' &&
121
- userIdStr === individualId
122
- ) {
112
+ if (this.config.primary === 'organization' && userIdStr === individualId) {
123
113
  return true;
124
114
  }
125
115
 
126
116
  // When primary is 'individual', also check linked organization user if required
127
- if (
128
- this.config.primary === 'individual' &&
129
- this.config.organizationUserRequired &&
130
- userIdStr === organizationId
131
- ) {
117
+ if (this.config.primary === 'individual' && this.config.organizationUserRequired && userIdStr === organizationId) {
132
118
  return true;
133
119
  }
134
120
 
@@ -136,4 +122,4 @@ class User {
136
122
  }
137
123
  }
138
124
 
139
- module.exports = { User };
125
+ module.exports = { User };
@@ -4,7 +4,7 @@ const PACKAGE_JSON = 'package.json';
4
4
 
5
5
  function findNearestBackendPackageJson() {
6
6
  let currentDir = process.cwd();
7
-
7
+
8
8
  // First check if we're in production by looking for package.json in the current directory
9
9
  const rootPackageJson = path.join(currentDir, PACKAGE_JSON);
10
10
  if (fs.existsSync(rootPackageJson)) {
@@ -35,4 +35,4 @@ function validateBackendPath(backendPath) {
35
35
  module.exports = {
36
36
  findNearestBackendPackageJson,
37
37
  validateBackendPath,
38
- };
38
+ };
package/utils/index.js CHANGED
@@ -1,7 +1,4 @@
1
- const {
2
- findNearestBackendPackageJson,
3
- validateBackendPath,
4
- } = require('./backend-path');
1
+ const { findNearestBackendPackageJson, validateBackendPath } = require('./backend-path');
5
2
 
6
3
  module.exports = {
7
4
  findNearestBackendPackageJson,
@@ -29,21 +29,13 @@ class WebsocketConnectionRepositoryDocumentDB extends WebsocketConnectionReposit
29
29
  createdAt: now,
30
30
  updatedAt: now,
31
31
  };
32
- const insertedId = await insertOne(
33
- this.prisma,
34
- 'WebsocketConnection',
35
- document
36
- );
37
- const created = await findOne(this.prisma, 'WebsocketConnection', {
38
- _id: insertedId,
39
- });
32
+ const insertedId = await insertOne(this.prisma, 'WebsocketConnection', document);
33
+ const created = await findOne(this.prisma, 'WebsocketConnection', { _id: insertedId });
40
34
  return this._mapConnection(created);
41
35
  }
42
36
 
43
37
  async deleteConnection(connectionId) {
44
- const result = await deleteOne(this.prisma, 'WebsocketConnection', {
45
- connectionId,
46
- });
38
+ const result = await deleteOne(this.prisma, 'WebsocketConnection', { connectionId });
47
39
  const deleted = result?.n ?? 0;
48
40
  return { acknowledged: true, deletedCount: deleted };
49
41
  }
@@ -74,10 +66,7 @@ class WebsocketConnectionRepositoryDocumentDB extends WebsocketConnectionReposit
74
66
  });
75
67
  await apigwManagementApi.send(command);
76
68
  } catch (error) {
77
- if (
78
- error.statusCode === 410 ||
79
- error.$metadata?.httpStatusCode === 410
80
- ) {
69
+ if (error.statusCode === 410 || error.$metadata?.httpStatusCode === 410) {
81
70
  console.log(`Stale connection ${conn.connectionId}`);
82
71
  await deleteMany(this.prisma, 'WebsocketConnection', {
83
72
  connectionId: conn.connectionId,
@@ -91,18 +80,14 @@ class WebsocketConnectionRepositoryDocumentDB extends WebsocketConnectionReposit
91
80
  }
92
81
 
93
82
  async findConnection(connectionId) {
94
- const doc = await findOne(this.prisma, 'WebsocketConnection', {
95
- connectionId,
96
- });
83
+ const doc = await findOne(this.prisma, 'WebsocketConnection', { connectionId });
97
84
  return doc ? this._mapConnection(doc) : null;
98
85
  }
99
86
 
100
87
  async findConnectionById(id) {
101
88
  const objectId = toObjectId(id);
102
89
  if (!objectId) return null;
103
- const doc = await findOne(this.prisma, 'WebsocketConnection', {
104
- _id: objectId,
105
- });
90
+ const doc = await findOne(this.prisma, 'WebsocketConnection', { _id: objectId });
106
91
  return doc ? this._mapConnection(doc) : null;
107
92
  }
108
93
 
@@ -130,3 +115,5 @@ class WebsocketConnectionRepositoryDocumentDB extends WebsocketConnectionReposit
130
115
  }
131
116
 
132
117
  module.exports = { WebsocketConnectionRepositoryDocumentDB };
118
+
119
+
@@ -77,10 +77,9 @@ class WebsocketConnectionRepositoryMongo extends WebsocketConnectionRepositoryIn
77
77
  return connections.map((conn) => ({
78
78
  connectionId: conn.connectionId,
79
79
  send: async (data) => {
80
- const apigwManagementApi =
81
- new ApiGatewayManagementApiClient({
82
- endpoint: process.env.WEBSOCKET_API_ENDPOINT,
83
- });
80
+ const apigwManagementApi = new ApiGatewayManagementApiClient({
81
+ endpoint: process.env.WEBSOCKET_API_ENDPOINT,
82
+ });
84
83
 
85
84
  try {
86
85
  const command = new PostToConnectionCommand({
@@ -89,10 +88,7 @@ class WebsocketConnectionRepositoryMongo extends WebsocketConnectionRepositoryIn
89
88
  });
90
89
  await apigwManagementApi.send(command);
91
90
  } catch (error) {
92
- if (
93
- error.statusCode === 410 ||
94
- error.$metadata?.httpStatusCode === 410
95
- ) {
91
+ if (error.statusCode === 410 || error.$metadata?.httpStatusCode === 410) {
96
92
  console.log(
97
93
  `Stale connection ${conn.connectionId}`
98
94
  );
@@ -111,10 +111,9 @@ class WebsocketConnectionRepositoryPostgres extends WebsocketConnectionRepositor
111
111
  return connections.map((conn) => ({
112
112
  connectionId: conn.connectionId,
113
113
  send: async (data) => {
114
- const apigwManagementApi =
115
- new ApiGatewayManagementApiClient({
116
- endpoint: process.env.WEBSOCKET_API_ENDPOINT,
117
- });
114
+ const apigwManagementApi = new ApiGatewayManagementApiClient({
115
+ endpoint: process.env.WEBSOCKET_API_ENDPOINT,
116
+ });
118
117
 
119
118
  try {
120
119
  const command = new PostToConnectionCommand({
@@ -123,10 +122,7 @@ class WebsocketConnectionRepositoryPostgres extends WebsocketConnectionRepositor
123
122
  });
124
123
  await apigwManagementApi.send(command);
125
124
  } catch (error) {
126
- if (
127
- error.statusCode === 410 ||
128
- error.$metadata?.httpStatusCode === 410
129
- ) {
125
+ if (error.statusCode === 410 || error.$metadata?.httpStatusCode === 410) {
130
126
  console.log(
131
127
  `Stale connection ${conn.connectionId}`
132
128
  );
@@ -82,10 +82,9 @@ class WebsocketConnectionRepository extends WebsocketConnectionRepositoryInterfa
82
82
  return connections.map((conn) => ({
83
83
  connectionId: conn.connectionId,
84
84
  send: async (data) => {
85
- const apigwManagementApi =
86
- new ApiGatewayManagementApiClient({
87
- endpoint: process.env.WEBSOCKET_API_ENDPOINT,
88
- });
85
+ const apigwManagementApi = new ApiGatewayManagementApiClient({
86
+ endpoint: process.env.WEBSOCKET_API_ENDPOINT,
87
+ });
89
88
 
90
89
  try {
91
90
  const command = new PostToConnectionCommand({
@@ -94,10 +93,7 @@ class WebsocketConnectionRepository extends WebsocketConnectionRepositoryInterfa
94
93
  });
95
94
  await apigwManagementApi.send(command);
96
95
  } catch (error) {
97
- if (
98
- error.statusCode === 410 ||
99
- error.$metadata?.httpStatusCode === 410
100
- ) {
96
+ if (error.statusCode === 410 || error.$metadata?.httpStatusCode === 410) {
101
97
  console.log(
102
98
  `Stale connection ${conn.connectionId}`
103
99
  );
@@ -1,121 +0,0 @@
1
- /**
2
- * Admin API Key Repository Interface
3
- * Abstract base class defining the contract for admin API key persistence adapters
4
- *
5
- * This follows the Port in Hexagonal Architecture:
6
- * - Domain layer depends on this abstraction
7
- * - Concrete adapters implement this interface
8
- * - Use cases receive repositories via dependency injection
9
- *
10
- * Admin API keys provide authentication for script execution and management endpoints.
11
- * Keys are bcrypt-hashed for security and support scoping and expiration.
12
- *
13
- * @abstract
14
- */
15
- class AdminApiKeyRepositoryInterface {
16
- /**
17
- * Create a new admin API key
18
- *
19
- * @param {Object} params - API key creation parameters
20
- * @param {string} params.name - Human-readable name for the key
21
- * @param {string} params.keyHash - bcrypt hash of the raw key
22
- * @param {string} params.keyLast4 - Last 4 characters of key (for display)
23
- * @param {string[]} params.scopes - Array of permission scopes (e.g., ['scripts:execute', 'scripts:read'])
24
- * @param {Date} [params.expiresAt] - Optional expiration date
25
- * @param {string} [params.createdBy] - Optional identifier of creator (user/admin)
26
- * @returns {Promise<Object>} The created API key record
27
- * @abstract
28
- */
29
- async createApiKey({
30
- name,
31
- keyHash,
32
- keyLast4,
33
- scopes,
34
- expiresAt,
35
- createdBy,
36
- }) {
37
- throw new Error('Method createApiKey must be implemented by subclass');
38
- }
39
-
40
- /**
41
- * Find an API key by its bcrypt hash
42
- * Used during authentication to validate incoming keys
43
- *
44
- * @param {string} keyHash - The bcrypt hash to search for
45
- * @returns {Promise<Object|null>} The API key record or null if not found
46
- * @abstract
47
- */
48
- async findApiKeyByHash(keyHash) {
49
- throw new Error(
50
- 'Method findApiKeyByHash must be implemented by subclass'
51
- );
52
- }
53
-
54
- /**
55
- * Find an API key by its ID
56
- *
57
- * @param {string|number} id - The API key ID
58
- * @returns {Promise<Object|null>} The API key record or null if not found
59
- * @abstract
60
- */
61
- async findApiKeyById(id) {
62
- throw new Error(
63
- 'Method findApiKeyById must be implemented by subclass'
64
- );
65
- }
66
-
67
- /**
68
- * Find all active (non-expired, non-deactivated) API keys
69
- * Used during authentication to check all valid keys
70
- *
71
- * @returns {Promise<Array>} Array of active API key records
72
- * @abstract
73
- */
74
- async findActiveApiKeys() {
75
- throw new Error(
76
- 'Method findActiveApiKeys must be implemented by subclass'
77
- );
78
- }
79
-
80
- /**
81
- * Update the lastUsedAt timestamp for an API key
82
- * Called after successful authentication
83
- *
84
- * @param {string|number} id - The API key ID
85
- * @returns {Promise<Object>} Updated API key record
86
- * @abstract
87
- */
88
- async updateApiKeyLastUsed(id) {
89
- throw new Error(
90
- 'Method updateApiKeyLastUsed must be implemented by subclass'
91
- );
92
- }
93
-
94
- /**
95
- * Deactivate an API key (soft delete)
96
- * Sets isActive to false, preventing further use
97
- *
98
- * @param {string|number} id - The API key ID
99
- * @returns {Promise<Object>} Updated API key record
100
- * @abstract
101
- */
102
- async deactivateApiKey(id) {
103
- throw new Error(
104
- 'Method deactivateApiKey must be implemented by subclass'
105
- );
106
- }
107
-
108
- /**
109
- * Delete an API key (hard delete)
110
- * Permanently removes the key from the database
111
- *
112
- * @param {string|number} id - The API key ID
113
- * @returns {Promise<Object>} Deletion result
114
- * @abstract
115
- */
116
- async deleteApiKey(id) {
117
- throw new Error('Method deleteApiKey must be implemented by subclass');
118
- }
119
- }
120
-
121
- module.exports = { AdminApiKeyRepositoryInterface };
@@ -1,155 +0,0 @@
1
- const { prisma } = require('../../database/prisma');
2
- const {
3
- AdminApiKeyRepositoryInterface,
4
- } = require('./admin-api-key-repository-interface');
5
-
6
- /**
7
- * MongoDB Admin API Key Repository Adapter
8
- * Handles admin API key persistence using Prisma with MongoDB
9
- *
10
- * MongoDB-specific characteristics:
11
- * - IDs are strings with @db.ObjectId
12
- * - Supports bcrypt hashed keys
13
- * - Scopes stored as String[] array
14
- */
15
- class AdminApiKeyRepositoryMongo extends AdminApiKeyRepositoryInterface {
16
- constructor() {
17
- super();
18
- this.prisma = prisma;
19
- }
20
-
21
- /**
22
- * Create a new admin API key
23
- *
24
- * @param {Object} params - API key creation parameters
25
- * @param {string} params.name - Human-readable name for the key
26
- * @param {string} params.keyHash - bcrypt hash of the raw key
27
- * @param {string} params.keyLast4 - Last 4 characters of key (for display)
28
- * @param {string[]} params.scopes - Array of permission scopes
29
- * @param {Date} [params.expiresAt] - Optional expiration date
30
- * @param {string} [params.createdBy] - Optional identifier of creator
31
- * @returns {Promise<Object>} The created API key record
32
- */
33
- async createApiKey({
34
- name,
35
- keyHash,
36
- keyLast4,
37
- scopes,
38
- expiresAt,
39
- createdBy,
40
- }) {
41
- const apiKey = await this.prisma.adminApiKey.create({
42
- data: {
43
- name,
44
- keyHash,
45
- keyLast4,
46
- scopes,
47
- expiresAt,
48
- createdBy,
49
- },
50
- });
51
-
52
- return apiKey;
53
- }
54
-
55
- /**
56
- * Find an API key by its bcrypt hash
57
- * Used during authentication to validate incoming keys
58
- *
59
- * @param {string} keyHash - The bcrypt hash to search for
60
- * @returns {Promise<Object|null>} The API key record or null if not found
61
- */
62
- async findApiKeyByHash(keyHash) {
63
- const apiKey = await this.prisma.adminApiKey.findUnique({
64
- where: { keyHash },
65
- });
66
-
67
- return apiKey;
68
- }
69
-
70
- /**
71
- * Find an API key by its ID
72
- *
73
- * @param {string} id - The API key ID (MongoDB ObjectId as string)
74
- * @returns {Promise<Object|null>} The API key record or null if not found
75
- */
76
- async findApiKeyById(id) {
77
- const apiKey = await this.prisma.adminApiKey.findUnique({
78
- where: { id },
79
- });
80
-
81
- return apiKey;
82
- }
83
-
84
- /**
85
- * Find all active (non-expired, non-deactivated) API keys
86
- * Used during authentication to check all valid keys
87
- *
88
- * @returns {Promise<Array>} Array of active API key records
89
- */
90
- async findActiveApiKeys() {
91
- const now = new Date();
92
- const apiKeys = await this.prisma.adminApiKey.findMany({
93
- where: {
94
- isActive: true,
95
- OR: [{ expiresAt: null }, { expiresAt: { gt: now } }],
96
- },
97
- });
98
-
99
- return apiKeys;
100
- }
101
-
102
- /**
103
- * Update the lastUsedAt timestamp for an API key
104
- * Called after successful authentication
105
- *
106
- * @param {string} id - The API key ID
107
- * @returns {Promise<Object>} Updated API key record
108
- */
109
- async updateApiKeyLastUsed(id) {
110
- const apiKey = await this.prisma.adminApiKey.update({
111
- where: { id },
112
- data: {
113
- lastUsedAt: new Date(),
114
- },
115
- });
116
-
117
- return apiKey;
118
- }
119
-
120
- /**
121
- * Deactivate an API key (soft delete)
122
- * Sets isActive to false, preventing further use
123
- *
124
- * @param {string} id - The API key ID
125
- * @returns {Promise<Object>} Updated API key record
126
- */
127
- async deactivateApiKey(id) {
128
- const apiKey = await this.prisma.adminApiKey.update({
129
- where: { id },
130
- data: {
131
- isActive: false,
132
- },
133
- });
134
-
135
- return apiKey;
136
- }
137
-
138
- /**
139
- * Delete an API key (hard delete)
140
- * Permanently removes the key from the database
141
- *
142
- * @param {string} id - The API key ID
143
- * @returns {Promise<Object>} Deletion result
144
- */
145
- async deleteApiKey(id) {
146
- await this.prisma.adminApiKey.delete({
147
- where: { id },
148
- });
149
-
150
- // Return Mongoose-compatible result
151
- return { acknowledged: true, deletedCount: 1 };
152
- }
153
- }
154
-
155
- module.exports = { AdminApiKeyRepositoryMongo };