@friggframework/core 2.0.0--canary.548.c8ae0ca.0 → 2.0.0--canary.545.c40eca4.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 (237) hide show
  1. package/CHANGELOG.md +66 -67
  2. package/CLAUDE.md +148 -124
  3. package/README.md +165 -130
  4. package/admin-scripts/index.js +52 -0
  5. package/admin-scripts/repositories/admin-api-key-repository-documentdb.js +21 -0
  6. package/admin-scripts/repositories/admin-api-key-repository-factory.js +51 -0
  7. package/admin-scripts/repositories/admin-api-key-repository-interface.js +121 -0
  8. package/admin-scripts/repositories/admin-api-key-repository-mongo.js +155 -0
  9. package/admin-scripts/repositories/admin-api-key-repository-postgres.js +189 -0
  10. package/admin-scripts/repositories/admin-process-repository-documentdb.js +21 -0
  11. package/admin-scripts/repositories/admin-process-repository-factory.js +49 -0
  12. package/admin-scripts/repositories/admin-process-repository-interface.js +150 -0
  13. package/admin-scripts/repositories/admin-process-repository-mongo.js +213 -0
  14. package/admin-scripts/repositories/admin-process-repository-postgres.js +251 -0
  15. package/admin-scripts/repositories/script-execution-repository-documentdb.js +21 -0
  16. package/admin-scripts/repositories/script-execution-repository-factory.js +51 -0
  17. package/admin-scripts/repositories/script-execution-repository-interface.js +193 -0
  18. package/admin-scripts/repositories/script-execution-repository-mongo.js +278 -0
  19. package/admin-scripts/repositories/script-execution-repository-postgres.js +320 -0
  20. package/admin-scripts/repositories/script-schedule-repository-documentdb.js +21 -0
  21. package/admin-scripts/repositories/script-schedule-repository-factory.js +49 -0
  22. package/admin-scripts/repositories/script-schedule-repository-interface.js +108 -0
  23. package/admin-scripts/repositories/script-schedule-repository-mongo.js +179 -0
  24. package/admin-scripts/repositories/script-schedule-repository-postgres.js +210 -0
  25. package/application/commands/admin-script-commands.js +348 -0
  26. package/application/commands/integration-commands.js +12 -6
  27. package/application/index.js +5 -3
  28. package/assertions/get.js +17 -7
  29. package/associations/association.js +59 -57
  30. package/core/CLAUDE.md +222 -156
  31. package/core/Worker.js +33 -12
  32. package/credential/credential-router.js +262 -0
  33. package/credential/repositories/credential-repository-documentdb.js +71 -1
  34. package/credential/repositories/credential-repository-factory.js +4 -6
  35. package/credential/repositories/credential-repository-interface.js +8 -2
  36. package/credential/repositories/credential-repository-mongo.js +45 -4
  37. package/credential/repositories/credential-repository-postgres.js +44 -3
  38. package/credential/repositories/credential-repository.js +3 -1
  39. package/credential/use-cases/delete-credential-for-user.js +50 -0
  40. package/credential/use-cases/get-credential-for-user.js +21 -3
  41. package/credential/use-cases/list-credentials-for-user.js +31 -0
  42. package/credential/use-cases/reauthorize-credential.js +103 -0
  43. package/credential/use-cases/update-authentication-status.js +5 -2
  44. package/database/MONGODB_TRANSACTION_FIX.md +72 -52
  45. package/database/config.js +13 -59
  46. package/database/documentdb-encryption-service.js +29 -13
  47. package/database/documentdb-utils.js +21 -12
  48. package/database/encryption/README.md +53 -36
  49. package/database/encryption/encryption-schema-registry.js +29 -23
  50. package/database/encryption/field-encryption-service.js +15 -4
  51. package/database/encryption/logger.js +3 -2
  52. package/database/encryption/prisma-encryption-extension.js +5 -8
  53. package/database/prisma.js +22 -14
  54. package/database/repositories/health-check-repository-factory.js +7 -5
  55. package/database/repositories/health-check-repository-interface.js +15 -5
  56. package/database/repositories/health-check-repository-postgres.js +1 -1
  57. package/database/use-cases/check-database-health-use-case.js +3 -2
  58. package/database/use-cases/check-database-state-use-case.js +8 -7
  59. package/database/use-cases/get-database-state-via-worker-use-case.js +15 -12
  60. package/database/use-cases/get-migration-status-use-case.js +4 -2
  61. package/database/use-cases/run-database-migration-use-case.js +41 -9
  62. package/database/use-cases/test-encryption-use-case.js +4 -5
  63. package/database/use-cases/trigger-database-migration-use-case.js +9 -8
  64. package/database/utils/mongodb-collection-utils.js +11 -3
  65. package/database/utils/mongodb-schema-init.js +10 -4
  66. package/database/utils/prisma-runner.js +144 -74
  67. package/database/utils/prisma-schema-parser.js +2 -2
  68. package/docs/PROCESS_MANAGEMENT_QUEUE_SPEC.md +135 -80
  69. package/encrypt/Cryptor.js +54 -49
  70. package/encrypt/aes-encryption-key-provider.js +82 -0
  71. package/encrypt/encryption-key-provider-interface.js +50 -0
  72. package/errors/fetch-error.js +1 -1
  73. package/generated/prisma-mongodb/edge.js +59 -4
  74. package/generated/prisma-mongodb/index-browser.js +49 -1
  75. package/generated/prisma-mongodb/index.d.ts +4023 -61
  76. package/generated/prisma-mongodb/index.js +59 -4
  77. package/generated/prisma-mongodb/package.json +1 -1
  78. package/generated/prisma-mongodb/schema.prisma +87 -0
  79. package/generated/prisma-mongodb/wasm.js +59 -4
  80. package/generated/prisma-postgresql/edge.js +58 -4
  81. package/generated/prisma-postgresql/index-browser.js +48 -1
  82. package/generated/prisma-postgresql/index.d.ts +4738 -54
  83. package/generated/prisma-postgresql/index.js +58 -4
  84. package/generated/prisma-postgresql/package.json +1 -1
  85. package/generated/prisma-postgresql/schema.prisma +85 -0
  86. package/generated/prisma-postgresql/wasm.js +58 -4
  87. package/handlers/WEBHOOKS.md +104 -81
  88. package/handlers/app-definition-loader.js +53 -10
  89. package/handlers/app-handler-helpers.js +14 -3
  90. package/handlers/backend-utils.js +0 -1
  91. package/handlers/database-migration-handler.js +64 -45
  92. package/handlers/middleware/admin-auth.js +53 -0
  93. package/handlers/routers/HEALTHCHECK.md +170 -135
  94. package/handlers/routers/admin.js +474 -0
  95. package/handlers/routers/auth.js +51 -9
  96. package/handlers/routers/db-migration.handler.js +2 -3
  97. package/handlers/routers/db-migration.js +102 -66
  98. package/handlers/routers/docs.js +180 -0
  99. package/handlers/routers/health.js +84 -283
  100. package/handlers/routers/integration-defined-routers.js +44 -33
  101. package/handlers/routers/integration-webhook-routers.js +73 -52
  102. package/handlers/routers/middleware/loadUser.js +39 -0
  103. package/handlers/routers/middleware/requireAdmin.js +43 -0
  104. package/handlers/routers/middleware/requireLoggedInUser.js +19 -0
  105. package/handlers/routers/user.js +30 -14
  106. package/handlers/routers/websocket.js +18 -4
  107. package/handlers/use-cases/check-integrations-health-use-case.js +13 -6
  108. package/handlers/workers/db-migration.js +74 -35
  109. package/handlers/workers/integration-defined-workers.js +31 -20
  110. package/index.js +50 -16
  111. package/infrastructure/scheduler/index.js +15 -11
  112. package/infrastructure/scheduler/netlify-scheduler-adapter.js +185 -0
  113. package/infrastructure/scheduler/scheduler-service-factory.js +38 -31
  114. package/integrations/WEBHOOK-QUICKSTART.md +21 -14
  115. package/integrations/index.js +4 -0
  116. package/integrations/integration-base.js +9 -6
  117. package/integrations/integration-router.js +1828 -157
  118. package/integrations/options.js +47 -20
  119. package/integrations/repositories/integration-mapping-repository-factory.js +4 -8
  120. package/integrations/repositories/integration-repository-documentdb.js +53 -24
  121. package/integrations/repositories/integration-repository-factory.js +6 -6
  122. package/integrations/repositories/integration-repository-interface.js +27 -9
  123. package/integrations/repositories/integration-repository-postgres.js +3 -3
  124. package/integrations/repositories/process-repository-factory.js +4 -7
  125. package/integrations/repositories/process-repository-interface.js +9 -5
  126. package/integrations/repositories/process-repository-mongo.js +7 -3
  127. package/integrations/repositories/process-repository-postgres.js +2 -2
  128. package/integrations/tests/doubles/config-capturing-integration.js +9 -8
  129. package/integrations/tests/doubles/dummy-integration-class.js +81 -8
  130. package/integrations/tests/doubles/test-integration-repository.js +51 -11
  131. package/integrations/use-cases/create-integration.js +36 -32
  132. package/integrations/use-cases/create-process.js +20 -9
  133. package/integrations/use-cases/delete-integration-for-user.js +5 -4
  134. package/integrations/use-cases/execute-proxy-request.js +564 -0
  135. package/integrations/use-cases/get-integration-for-user.js +25 -10
  136. package/integrations/use-cases/get-integration-instance-by-definition.js +13 -7
  137. package/integrations/use-cases/get-integrations-for-user.js +4 -1
  138. package/integrations/use-cases/get-possible-integrations.js +1 -1
  139. package/integrations/use-cases/get-process.js +5 -6
  140. package/integrations/use-cases/index.js +3 -1
  141. package/integrations/use-cases/load-integration-context.js +1 -5
  142. package/integrations/use-cases/update-process-state.js +10 -8
  143. package/integrations/utils/map-integration-dto.js +9 -3
  144. package/jest-setup.js +1 -1
  145. package/jest-teardown.js +1 -1
  146. package/lambda/TimeoutCatcher.js +32 -30
  147. package/lambda/index.js +1 -1
  148. package/logs/index.js +3 -3
  149. package/modules/domain/entities/AuthorizationSession.js +131 -0
  150. package/modules/domain/entities/index.js +10 -0
  151. package/modules/module.js +4 -9
  152. package/modules/repositories/authorization-session-repository-factory.js +53 -0
  153. package/modules/repositories/authorization-session-repository-interface.js +75 -0
  154. package/modules/repositories/authorization-session-repository-mongo.js +169 -0
  155. package/modules/repositories/authorization-session-repository-postgres.js +170 -0
  156. package/modules/repositories/module-repository-documentdb.js +89 -41
  157. package/modules/repositories/module-repository-factory.js +4 -6
  158. package/modules/repositories/module-repository-interface.js +13 -0
  159. package/modules/repositories/module-repository-mongo.js +40 -5
  160. package/modules/repositories/module-repository-postgres.js +42 -5
  161. package/modules/repositories/module-repository.js +28 -0
  162. package/modules/requester/api-key.js +0 -2
  163. package/modules/requester/basic.js +0 -1
  164. package/modules/requester/oauth-2.js +3 -14
  165. package/modules/test/mock-api/definition.js +15 -10
  166. package/modules/test/mock-api/mocks/hubspot.js +36 -36
  167. package/modules/tests/doubles/test-module-factory.js +10 -4
  168. package/modules/tests/doubles/test-module-repository.js +1 -1
  169. package/modules/use-cases/delete-module-entity.js +23 -0
  170. package/modules/use-cases/get-authorization-requirements.js +110 -0
  171. package/modules/use-cases/get-entities-for-user.js +1 -1
  172. package/modules/use-cases/get-entity-options-by-id.js +8 -6
  173. package/modules/use-cases/get-module-entity-by-id.js +16 -0
  174. package/modules/use-cases/get-module.js +12 -9
  175. package/modules/use-cases/process-authorization-callback.js +12 -6
  176. package/modules/use-cases/process-authorization-step.js +160 -0
  177. package/modules/use-cases/refresh-entity-options.js +8 -6
  178. package/modules/use-cases/start-authorization-session.js +86 -0
  179. package/modules/use-cases/test-module-auth.js +8 -6
  180. package/modules/use-cases/update-module-entity.js +27 -0
  181. package/modules/utils/map-module-dto.js +2 -2
  182. package/openapi/openapi-spec-generator.js +370 -0
  183. package/openapi/openapi-v1.yaml +1360 -0
  184. package/openapi/openapi-v2.yaml +1535 -0
  185. package/package.json +7 -9
  186. package/prisma-mongodb/schema.prisma +87 -0
  187. package/prisma-postgresql/migrations/20260222000000_add_admin_process_and_script_schedule/migration.sql +55 -0
  188. package/prisma-postgresql/schema.prisma +85 -0
  189. package/providers/index.js +13 -0
  190. package/providers/resolve-provider.js +93 -0
  191. package/queues/index.js +19 -0
  192. package/queues/providers/index.js +7 -0
  193. package/queues/providers/netlify-background-provider.js +76 -0
  194. package/queues/providers/qstash-queue-provider.js +122 -0
  195. package/queues/queue-client-interface.js +55 -0
  196. package/queues/queue-provider-factory.js +93 -0
  197. package/queues/queue-provider.js +46 -0
  198. package/queues/queuer-util.js +33 -25
  199. package/syncs/repositories/sync-repository-documentdb.js +39 -19
  200. package/syncs/repositories/sync-repository-factory.js +4 -4
  201. package/syncs/repositories/sync-repository-interface.js +6 -2
  202. package/syncs/repositories/sync-repository-postgres.js +19 -13
  203. package/syncs/sync.js +104 -100
  204. package/token/repositories/token-repository-factory.js +4 -6
  205. package/types/assertions/index.d.ts +72 -72
  206. package/types/core/index.d.ts +98 -53
  207. package/types/errors/index.d.ts +61 -54
  208. package/types/eslint-config/index.d.ts +40 -40
  209. package/types/lambda/index.d.ts +26 -26
  210. package/types/logs/index.d.ts +4 -4
  211. package/types/prettier-config/index.d.ts +5 -5
  212. package/types/test-environment/index.d.ts +14 -14
  213. package/types/tsconfig.json +95 -93
  214. package/user/repositories/user-repository-factory.js +4 -4
  215. package/user/tests/doubles/test-user-repository.js +5 -2
  216. package/user/use-cases/authenticate-user.js +2 -4
  217. package/user/use-cases/authenticate-with-shared-secret.js +1 -1
  218. package/user/use-cases/create-individual-user.js +8 -7
  219. package/user/use-cases/create-organization-user.js +1 -1
  220. package/user/use-cases/create-token-for-user-id.js +1 -1
  221. package/user/use-cases/delete-user.js +47 -0
  222. package/user/use-cases/get-user-from-adopter-jwt.js +0 -2
  223. package/user/use-cases/get-user-from-bearer-token.js +7 -3
  224. package/user/use-cases/get-user-from-x-frigg-headers.js +14 -11
  225. package/user/use-cases/login-user.js +8 -8
  226. package/user/user.js +18 -4
  227. package/utils/backend-path.js +2 -2
  228. package/utils/index.js +4 -1
  229. package/websocket/repositories/websocket-connection-repository-documentdb.js +46 -21
  230. package/websocket/repositories/websocket-connection-repository-factory.js +4 -8
  231. package/websocket/repositories/websocket-connection-repository-mongo.js +26 -16
  232. package/websocket/repositories/websocket-connection-repository-postgres.js +26 -15
  233. package/websocket/repositories/websocket-connection-repository.js +26 -20
  234. package/websocket/websocket-message-sender-interface.js +38 -0
  235. package/database/adapters/lambda-invoker.js +0 -97
  236. package/database/repositories/migration-status-repository-s3.js +0 -137
  237. package/infrastructure/scheduler/eventbridge-scheduler-adapter.js +0 -184
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Script Execution Repository Interface
3
+ * Abstract base class defining the contract for script execution 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
+ * Script executions track the lifecycle of admin script runs, including:
11
+ * - Input parameters and output results
12
+ * - Execution status and error details
13
+ * - Performance metrics
14
+ * - Audit trail (who triggered, when, from where)
15
+ * - Real-time logs
16
+ *
17
+ * @abstract
18
+ */
19
+ class ScriptExecutionRepositoryInterface {
20
+ /**
21
+ * Create a new script execution record
22
+ *
23
+ * @param {Object} params - Execution creation parameters
24
+ * @param {string} params.scriptName - Name of the script being executed
25
+ * @param {string} [params.scriptVersion] - Version of the script
26
+ * @param {string} params.trigger - Trigger type ('MANUAL', 'SCHEDULED', 'QUEUE', 'WEBHOOK')
27
+ * @param {string} [params.mode] - Execution mode ('sync' or 'async', default 'async')
28
+ * @param {Object} [params.input] - Input parameters for the script
29
+ * @param {Object} [params.audit] - Audit information
30
+ * @param {string} [params.audit.apiKeyName] - Name of API key used
31
+ * @param {string} [params.audit.apiKeyLast4] - Last 4 chars of API key
32
+ * @param {string} [params.audit.ipAddress] - IP address of requester
33
+ * @returns {Promise<Object>} The created execution record
34
+ * @abstract
35
+ */
36
+ async createExecution({
37
+ scriptName,
38
+ scriptVersion,
39
+ trigger,
40
+ mode,
41
+ input,
42
+ audit,
43
+ }) {
44
+ throw new Error(
45
+ 'Method createExecution must be implemented by subclass'
46
+ );
47
+ }
48
+
49
+ /**
50
+ * Find an execution by its ID
51
+ *
52
+ * @param {string|number} id - The execution ID
53
+ * @returns {Promise<Object|null>} The execution record or null if not found
54
+ * @abstract
55
+ */
56
+ async findExecutionById(id) {
57
+ throw new Error(
58
+ 'Method findExecutionById must be implemented by subclass'
59
+ );
60
+ }
61
+
62
+ /**
63
+ * Find all executions for a specific script
64
+ *
65
+ * @param {string} scriptName - The script name to filter by
66
+ * @param {Object} [options] - Query options
67
+ * @param {number} [options.limit] - Maximum number of results
68
+ * @param {number} [options.offset] - Number of results to skip
69
+ * @param {string} [options.sortBy] - Field to sort by
70
+ * @param {string} [options.sortOrder] - Sort order ('asc' or 'desc')
71
+ * @returns {Promise<Array>} Array of execution records
72
+ * @abstract
73
+ */
74
+ async findExecutionsByScriptName(scriptName, options = {}) {
75
+ throw new Error(
76
+ 'Method findExecutionsByScriptName must be implemented by subclass'
77
+ );
78
+ }
79
+
80
+ /**
81
+ * Find all executions with a specific status
82
+ *
83
+ * @param {string} status - Status to filter by ('PENDING', 'RUNNING', 'COMPLETED', 'FAILED', 'TIMEOUT', 'CANCELLED')
84
+ * @param {Object} [options] - Query options
85
+ * @param {number} [options.limit] - Maximum number of results
86
+ * @param {number} [options.offset] - Number of results to skip
87
+ * @param {string} [options.sortBy] - Field to sort by
88
+ * @param {string} [options.sortOrder] - Sort order ('asc' or 'desc')
89
+ * @returns {Promise<Array>} Array of execution records
90
+ * @abstract
91
+ */
92
+ async findExecutionsByStatus(status, options = {}) {
93
+ throw new Error(
94
+ 'Method findExecutionsByStatus must be implemented by subclass'
95
+ );
96
+ }
97
+
98
+ /**
99
+ * Update the status of an execution
100
+ *
101
+ * @param {string|number} id - The execution ID
102
+ * @param {string} status - New status value
103
+ * @returns {Promise<Object>} Updated execution record
104
+ * @abstract
105
+ */
106
+ async updateExecutionStatus(id, status) {
107
+ throw new Error(
108
+ 'Method updateExecutionStatus must be implemented by subclass'
109
+ );
110
+ }
111
+
112
+ /**
113
+ * Update the output result of an execution
114
+ *
115
+ * @param {string|number} id - The execution ID
116
+ * @param {Object} output - Output data from the script
117
+ * @returns {Promise<Object>} Updated execution record
118
+ * @abstract
119
+ */
120
+ async updateExecutionOutput(id, output) {
121
+ throw new Error(
122
+ 'Method updateExecutionOutput must be implemented by subclass'
123
+ );
124
+ }
125
+
126
+ /**
127
+ * Update the error details of a failed execution
128
+ *
129
+ * @param {string|number} id - The execution ID
130
+ * @param {Object} error - Error information
131
+ * @param {string} error.name - Error name/type
132
+ * @param {string} error.message - Error message
133
+ * @param {string} [error.stack] - Error stack trace
134
+ * @returns {Promise<Object>} Updated execution record
135
+ * @abstract
136
+ */
137
+ async updateExecutionError(id, error) {
138
+ throw new Error(
139
+ 'Method updateExecutionError must be implemented by subclass'
140
+ );
141
+ }
142
+
143
+ /**
144
+ * Update the performance metrics of an execution
145
+ *
146
+ * @param {string|number} id - The execution ID
147
+ * @param {Object} metrics - Performance metrics
148
+ * @param {Date} [metrics.startTime] - Execution start time
149
+ * @param {Date} [metrics.endTime] - Execution end time
150
+ * @param {number} [metrics.durationMs] - Duration in milliseconds
151
+ * @returns {Promise<Object>} Updated execution record
152
+ * @abstract
153
+ */
154
+ async updateExecutionMetrics(id, metrics) {
155
+ throw new Error(
156
+ 'Method updateExecutionMetrics must be implemented by subclass'
157
+ );
158
+ }
159
+
160
+ /**
161
+ * Append a log entry to an execution's log array
162
+ *
163
+ * @param {string|number} id - The execution ID
164
+ * @param {Object} logEntry - Log entry to append
165
+ * @param {string} logEntry.level - Log level ('debug', 'info', 'warn', 'error')
166
+ * @param {string} logEntry.message - Log message
167
+ * @param {Object} [logEntry.data] - Additional log data
168
+ * @param {string} logEntry.timestamp - ISO timestamp
169
+ * @returns {Promise<Object>} Updated execution record
170
+ * @abstract
171
+ */
172
+ async appendExecutionLog(id, logEntry) {
173
+ throw new Error(
174
+ 'Method appendExecutionLog must be implemented by subclass'
175
+ );
176
+ }
177
+
178
+ /**
179
+ * Delete all executions older than a specific date
180
+ * Used for cleanup and retention policies
181
+ *
182
+ * @param {Date} date - Delete executions older than this date
183
+ * @returns {Promise<Object>} Deletion result with count
184
+ * @abstract
185
+ */
186
+ async deleteExecutionsOlderThan(date) {
187
+ throw new Error(
188
+ 'Method deleteExecutionsOlderThan must be implemented by subclass'
189
+ );
190
+ }
191
+ }
192
+
193
+ module.exports = { ScriptExecutionRepositoryInterface };
@@ -0,0 +1,278 @@
1
+ const { prisma } = require('../../database/prisma');
2
+ const {
3
+ ScriptExecutionRepositoryInterface,
4
+ } = require('./script-execution-repository-interface');
5
+
6
+ /**
7
+ * MongoDB Script Execution Repository Adapter
8
+ * Handles script execution persistence using Prisma with MongoDB
9
+ *
10
+ * MongoDB-specific characteristics:
11
+ * - IDs are strings with @db.ObjectId
12
+ * - logs field is Json[] - supports push operations
13
+ * - Audit fields stored as separate columns
14
+ */
15
+ class ScriptExecutionRepositoryMongo extends ScriptExecutionRepositoryInterface {
16
+ constructor() {
17
+ super();
18
+ this.prisma = prisma;
19
+ }
20
+
21
+ /**
22
+ * Create a new script execution record
23
+ *
24
+ * @param {Object} params - Execution creation parameters
25
+ * @param {string} params.scriptName - Name of the script being executed
26
+ * @param {string} [params.scriptVersion] - Version of the script
27
+ * @param {string} params.trigger - Trigger type
28
+ * @param {string} [params.mode] - Execution mode ('sync' or 'async', default 'async')
29
+ * @param {Object} [params.input] - Input parameters for the script
30
+ * @param {Object} [params.audit] - Audit information
31
+ * @param {string} [params.audit.apiKeyName] - Name of API key used
32
+ * @param {string} [params.audit.apiKeyLast4] - Last 4 chars of API key
33
+ * @param {string} [params.audit.ipAddress] - IP address of requester
34
+ * @returns {Promise<Object>} The created execution record
35
+ */
36
+ async createExecution({
37
+ scriptName,
38
+ scriptVersion,
39
+ trigger,
40
+ mode,
41
+ input,
42
+ audit,
43
+ }) {
44
+ const data = {
45
+ scriptName,
46
+ scriptVersion,
47
+ trigger,
48
+ mode: mode || 'async',
49
+ input,
50
+ logs: [],
51
+ };
52
+
53
+ // Map audit object to separate fields
54
+ if (audit) {
55
+ if (audit.apiKeyName) data.auditApiKeyName = audit.apiKeyName;
56
+ if (audit.apiKeyLast4) data.auditApiKeyLast4 = audit.apiKeyLast4;
57
+ if (audit.ipAddress) data.auditIpAddress = audit.ipAddress;
58
+ }
59
+
60
+ const execution = await this.prisma.scriptExecution.create({
61
+ data,
62
+ });
63
+
64
+ return execution;
65
+ }
66
+
67
+ /**
68
+ * Find an execution by its ID
69
+ *
70
+ * @param {string} id - The execution ID
71
+ * @returns {Promise<Object|null>} The execution record or null if not found
72
+ */
73
+ async findExecutionById(id) {
74
+ const execution = await this.prisma.scriptExecution.findUnique({
75
+ where: { id },
76
+ });
77
+
78
+ return execution;
79
+ }
80
+
81
+ /**
82
+ * Find all executions for a specific script
83
+ *
84
+ * @param {string} scriptName - The script name to filter by
85
+ * @param {Object} [options] - Query options
86
+ * @param {number} [options.limit] - Maximum number of results
87
+ * @param {number} [options.offset] - Number of results to skip
88
+ * @param {string} [options.sortBy] - Field to sort by
89
+ * @param {string} [options.sortOrder] - Sort order ('asc' or 'desc')
90
+ * @returns {Promise<Array>} Array of execution records
91
+ */
92
+ async findExecutionsByScriptName(scriptName, options = {}) {
93
+ const {
94
+ limit,
95
+ offset,
96
+ sortBy = 'createdAt',
97
+ sortOrder = 'desc',
98
+ } = options;
99
+
100
+ const executions = await this.prisma.scriptExecution.findMany({
101
+ where: { scriptName },
102
+ orderBy: { [sortBy]: sortOrder },
103
+ take: limit,
104
+ skip: offset,
105
+ });
106
+
107
+ return executions;
108
+ }
109
+
110
+ /**
111
+ * Find all executions with a specific status
112
+ *
113
+ * @param {string} status - Status to filter by
114
+ * @param {Object} [options] - Query options
115
+ * @param {number} [options.limit] - Maximum number of results
116
+ * @param {number} [options.offset] - Number of results to skip
117
+ * @param {string} [options.sortBy] - Field to sort by
118
+ * @param {string} [options.sortOrder] - Sort order ('asc' or 'desc')
119
+ * @returns {Promise<Array>} Array of execution records
120
+ */
121
+ async findExecutionsByStatus(status, options = {}) {
122
+ const {
123
+ limit,
124
+ offset,
125
+ sortBy = 'createdAt',
126
+ sortOrder = 'desc',
127
+ } = options;
128
+
129
+ const executions = await this.prisma.scriptExecution.findMany({
130
+ where: { status },
131
+ orderBy: { [sortBy]: sortOrder },
132
+ take: limit,
133
+ skip: offset,
134
+ });
135
+
136
+ return executions;
137
+ }
138
+
139
+ /**
140
+ * Update the status of an execution
141
+ *
142
+ * @param {string} id - The execution ID
143
+ * @param {string} status - New status value
144
+ * @returns {Promise<Object>} Updated execution record
145
+ */
146
+ async updateExecutionStatus(id, status) {
147
+ const execution = await this.prisma.scriptExecution.update({
148
+ where: { id },
149
+ data: { status },
150
+ });
151
+
152
+ return execution;
153
+ }
154
+
155
+ /**
156
+ * Update the output result of an execution
157
+ *
158
+ * @param {string} id - The execution ID
159
+ * @param {Object} output - Output data from the script
160
+ * @returns {Promise<Object>} Updated execution record
161
+ */
162
+ async updateExecutionOutput(id, output) {
163
+ const execution = await this.prisma.scriptExecution.update({
164
+ where: { id },
165
+ data: { output },
166
+ });
167
+
168
+ return execution;
169
+ }
170
+
171
+ /**
172
+ * Update the error details of a failed execution
173
+ *
174
+ * @param {string} id - The execution ID
175
+ * @param {Object} error - Error information
176
+ * @param {string} error.name - Error name/type
177
+ * @param {string} error.message - Error message
178
+ * @param {string} [error.stack] - Error stack trace
179
+ * @returns {Promise<Object>} Updated execution record
180
+ */
181
+ async updateExecutionError(id, error) {
182
+ const execution = await this.prisma.scriptExecution.update({
183
+ where: { id },
184
+ data: {
185
+ errorName: error.name,
186
+ errorMessage: error.message,
187
+ errorStack: error.stack,
188
+ },
189
+ });
190
+
191
+ return execution;
192
+ }
193
+
194
+ /**
195
+ * Update the performance metrics of an execution
196
+ *
197
+ * @param {string} id - The execution ID
198
+ * @param {Object} metrics - Performance metrics
199
+ * @param {Date} [metrics.startTime] - Execution start time
200
+ * @param {Date} [metrics.endTime] - Execution end time
201
+ * @param {number} [metrics.durationMs] - Duration in milliseconds
202
+ * @returns {Promise<Object>} Updated execution record
203
+ */
204
+ async updateExecutionMetrics(id, metrics) {
205
+ const data = {};
206
+ if (metrics.startTime !== undefined)
207
+ data.metricsStartTime = metrics.startTime;
208
+ if (metrics.endTime !== undefined)
209
+ data.metricsEndTime = metrics.endTime;
210
+ if (metrics.durationMs !== undefined)
211
+ data.metricsDurationMs = metrics.durationMs;
212
+
213
+ const execution = await this.prisma.scriptExecution.update({
214
+ where: { id },
215
+ data,
216
+ });
217
+
218
+ return execution;
219
+ }
220
+
221
+ /**
222
+ * Append a log entry to an execution's log array
223
+ *
224
+ * @param {string} id - The execution ID
225
+ * @param {Object} logEntry - Log entry to append
226
+ * @param {string} logEntry.level - Log level ('debug', 'info', 'warn', 'error')
227
+ * @param {string} logEntry.message - Log message
228
+ * @param {Object} [logEntry.data] - Additional log data
229
+ * @param {string} logEntry.timestamp - ISO timestamp
230
+ * @returns {Promise<Object>} Updated execution record
231
+ */
232
+ async appendExecutionLog(id, logEntry) {
233
+ // Get current execution
234
+ const execution = await this.prisma.scriptExecution.findUnique({
235
+ where: { id },
236
+ });
237
+
238
+ if (!execution) {
239
+ throw new Error(`Execution ${id} not found`);
240
+ }
241
+
242
+ // Append log entry to logs array (copy to avoid mutating original)
243
+ const logs = Array.isArray(execution.logs) ? [...execution.logs] : [];
244
+ logs.push(logEntry);
245
+
246
+ // Update with new logs array
247
+ const updated = await this.prisma.scriptExecution.update({
248
+ where: { id },
249
+ data: { logs },
250
+ });
251
+
252
+ return updated;
253
+ }
254
+
255
+ /**
256
+ * Delete all executions older than a specific date
257
+ * Used for cleanup and retention policies
258
+ *
259
+ * @param {Date} date - Delete executions older than this date
260
+ * @returns {Promise<Object>} Deletion result with count
261
+ */
262
+ async deleteExecutionsOlderThan(date) {
263
+ const result = await this.prisma.scriptExecution.deleteMany({
264
+ where: {
265
+ createdAt: {
266
+ lt: date,
267
+ },
268
+ },
269
+ });
270
+
271
+ return {
272
+ acknowledged: true,
273
+ deletedCount: result.count,
274
+ };
275
+ }
276
+ }
277
+
278
+ module.exports = { ScriptExecutionRepositoryMongo };