@friggframework/core 2.0.0-next.45 → 2.0.0-next.46

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 (163) hide show
  1. package/README.md +28 -0
  2. package/application/commands/integration-commands.js +19 -0
  3. package/core/Worker.js +8 -21
  4. package/credential/repositories/credential-repository-mongo.js +14 -8
  5. package/credential/repositories/credential-repository-postgres.js +14 -8
  6. package/credential/repositories/credential-repository.js +3 -8
  7. package/database/MONGODB_TRANSACTION_FIX.md +198 -0
  8. package/database/adapters/lambda-invoker.js +97 -0
  9. package/database/config.js +11 -2
  10. package/database/models/WebsocketConnection.js +11 -10
  11. package/database/prisma.js +63 -3
  12. package/database/repositories/health-check-repository-mongodb.js +3 -0
  13. package/database/repositories/migration-status-repository-s3.js +137 -0
  14. package/database/use-cases/check-database-state-use-case.js +81 -0
  15. package/database/use-cases/check-encryption-health-use-case.js +3 -2
  16. package/database/use-cases/get-database-state-via-worker-use-case.js +61 -0
  17. package/database/use-cases/get-migration-status-use-case.js +93 -0
  18. package/database/use-cases/run-database-migration-use-case.js +137 -0
  19. package/database/use-cases/trigger-database-migration-use-case.js +157 -0
  20. package/database/utils/mongodb-collection-utils.js +91 -0
  21. package/database/utils/mongodb-schema-init.js +106 -0
  22. package/database/utils/prisma-runner.js +400 -0
  23. package/database/utils/prisma-schema-parser.js +182 -0
  24. package/encrypt/Cryptor.js +14 -16
  25. package/generated/prisma-mongodb/client.d.ts +1 -0
  26. package/generated/prisma-mongodb/client.js +4 -0
  27. package/generated/prisma-mongodb/default.d.ts +1 -0
  28. package/generated/prisma-mongodb/default.js +4 -0
  29. package/generated/prisma-mongodb/edge.d.ts +1 -0
  30. package/generated/prisma-mongodb/edge.js +334 -0
  31. package/generated/prisma-mongodb/index-browser.js +316 -0
  32. package/generated/prisma-mongodb/index.d.ts +22897 -0
  33. package/generated/prisma-mongodb/index.js +359 -0
  34. package/generated/prisma-mongodb/package.json +183 -0
  35. package/generated/prisma-mongodb/query-engine-debian-openssl-3.0.x +0 -0
  36. package/generated/prisma-mongodb/query-engine-rhel-openssl-3.0.x +0 -0
  37. package/generated/prisma-mongodb/runtime/binary.d.ts +1 -0
  38. package/generated/prisma-mongodb/runtime/binary.js +289 -0
  39. package/generated/prisma-mongodb/runtime/edge-esm.js +34 -0
  40. package/generated/prisma-mongodb/runtime/edge.js +34 -0
  41. package/generated/prisma-mongodb/runtime/index-browser.d.ts +370 -0
  42. package/generated/prisma-mongodb/runtime/index-browser.js +16 -0
  43. package/generated/prisma-mongodb/runtime/library.d.ts +3977 -0
  44. package/generated/prisma-mongodb/runtime/react-native.js +83 -0
  45. package/generated/prisma-mongodb/runtime/wasm-compiler-edge.js +84 -0
  46. package/generated/prisma-mongodb/runtime/wasm-engine-edge.js +36 -0
  47. package/generated/prisma-mongodb/schema.prisma +362 -0
  48. package/generated/prisma-mongodb/wasm-edge-light-loader.mjs +4 -0
  49. package/generated/prisma-mongodb/wasm-worker-loader.mjs +4 -0
  50. package/generated/prisma-mongodb/wasm.d.ts +1 -0
  51. package/generated/prisma-mongodb/wasm.js +341 -0
  52. package/generated/prisma-postgresql/client.d.ts +1 -0
  53. package/generated/prisma-postgresql/client.js +4 -0
  54. package/generated/prisma-postgresql/default.d.ts +1 -0
  55. package/generated/prisma-postgresql/default.js +4 -0
  56. package/generated/prisma-postgresql/edge.d.ts +1 -0
  57. package/generated/prisma-postgresql/edge.js +356 -0
  58. package/generated/prisma-postgresql/index-browser.js +338 -0
  59. package/generated/prisma-postgresql/index.d.ts +25071 -0
  60. package/generated/prisma-postgresql/index.js +381 -0
  61. package/generated/prisma-postgresql/package.json +183 -0
  62. package/generated/prisma-postgresql/query-engine-debian-openssl-3.0.x +0 -0
  63. package/generated/prisma-postgresql/query-engine-rhel-openssl-3.0.x +0 -0
  64. package/generated/prisma-postgresql/query_engine_bg.js +2 -0
  65. package/generated/prisma-postgresql/query_engine_bg.wasm +0 -0
  66. package/generated/prisma-postgresql/runtime/binary.d.ts +1 -0
  67. package/generated/prisma-postgresql/runtime/binary.js +289 -0
  68. package/generated/prisma-postgresql/runtime/edge-esm.js +34 -0
  69. package/generated/prisma-postgresql/runtime/edge.js +34 -0
  70. package/generated/prisma-postgresql/runtime/index-browser.d.ts +370 -0
  71. package/generated/prisma-postgresql/runtime/index-browser.js +16 -0
  72. package/generated/prisma-postgresql/runtime/library.d.ts +3977 -0
  73. package/generated/prisma-postgresql/runtime/react-native.js +83 -0
  74. package/generated/prisma-postgresql/runtime/wasm-compiler-edge.js +84 -0
  75. package/generated/prisma-postgresql/runtime/wasm-engine-edge.js +36 -0
  76. package/generated/prisma-postgresql/schema.prisma +345 -0
  77. package/generated/prisma-postgresql/wasm-edge-light-loader.mjs +4 -0
  78. package/generated/prisma-postgresql/wasm-worker-loader.mjs +4 -0
  79. package/generated/prisma-postgresql/wasm.d.ts +1 -0
  80. package/generated/prisma-postgresql/wasm.js +363 -0
  81. package/handlers/database-migration-handler.js +227 -0
  82. package/handlers/routers/auth.js +1 -1
  83. package/handlers/routers/db-migration.handler.js +29 -0
  84. package/handlers/routers/db-migration.js +256 -0
  85. package/handlers/routers/health.js +41 -6
  86. package/handlers/routers/integration-webhook-routers.js +2 -2
  87. package/handlers/use-cases/check-integrations-health-use-case.js +22 -10
  88. package/handlers/workers/db-migration.js +352 -0
  89. package/index.js +12 -0
  90. package/integrations/integration-router.js +60 -70
  91. package/integrations/repositories/integration-repository-interface.js +12 -0
  92. package/integrations/repositories/integration-repository-mongo.js +32 -0
  93. package/integrations/repositories/integration-repository-postgres.js +33 -0
  94. package/integrations/repositories/process-repository-postgres.js +2 -2
  95. package/integrations/tests/doubles/test-integration-repository.js +2 -2
  96. package/logs/logger.js +0 -4
  97. package/modules/entity.js +0 -1
  98. package/modules/repositories/module-repository-mongo.js +3 -12
  99. package/modules/repositories/module-repository-postgres.js +0 -11
  100. package/modules/repositories/module-repository.js +1 -12
  101. package/modules/use-cases/get-entity-options-by-id.js +1 -1
  102. package/modules/use-cases/get-module.js +1 -2
  103. package/modules/use-cases/refresh-entity-options.js +1 -1
  104. package/modules/use-cases/test-module-auth.js +1 -1
  105. package/package.json +82 -66
  106. package/prisma-mongodb/schema.prisma +21 -21
  107. package/prisma-postgresql/schema.prisma +15 -15
  108. package/queues/queuer-util.js +24 -21
  109. package/types/core/index.d.ts +2 -2
  110. package/types/module-plugin/index.d.ts +0 -2
  111. package/user/use-cases/authenticate-user.js +127 -0
  112. package/user/use-cases/authenticate-with-shared-secret.js +48 -0
  113. package/user/use-cases/get-user-from-adopter-jwt.js +149 -0
  114. package/user/use-cases/get-user-from-x-frigg-headers.js +106 -0
  115. package/user/user.js +16 -0
  116. package/websocket/repositories/websocket-connection-repository-mongo.js +11 -10
  117. package/websocket/repositories/websocket-connection-repository-postgres.js +11 -10
  118. package/websocket/repositories/websocket-connection-repository.js +11 -10
  119. package/application/commands/integration-commands.test.js +0 -123
  120. package/database/encryption/encryption-integration.test.js +0 -553
  121. package/database/encryption/encryption-schema-registry.test.js +0 -392
  122. package/database/encryption/field-encryption-service.test.js +0 -525
  123. package/database/encryption/mongo-decryption-fix-verification.test.js +0 -348
  124. package/database/encryption/postgres-decryption-fix-verification.test.js +0 -371
  125. package/database/encryption/postgres-relation-decryption.test.js +0 -245
  126. package/database/encryption/prisma-encryption-extension.test.js +0 -439
  127. package/errors/base-error.test.js +0 -32
  128. package/errors/fetch-error.test.js +0 -79
  129. package/errors/halt-error.test.js +0 -11
  130. package/errors/validation-errors.test.js +0 -120
  131. package/handlers/auth-flow.integration.test.js +0 -147
  132. package/handlers/integration-event-dispatcher.test.js +0 -209
  133. package/handlers/routers/health.test.js +0 -210
  134. package/handlers/routers/integration-webhook-routers.test.js +0 -126
  135. package/handlers/webhook-flow.integration.test.js +0 -356
  136. package/handlers/workers/integration-defined-workers.test.js +0 -184
  137. package/integrations/tests/use-cases/create-integration.test.js +0 -131
  138. package/integrations/tests/use-cases/delete-integration-for-user.test.js +0 -150
  139. package/integrations/tests/use-cases/find-integration-context-by-external-entity-id.test.js +0 -92
  140. package/integrations/tests/use-cases/get-integration-for-user.test.js +0 -150
  141. package/integrations/tests/use-cases/get-integration-instance.test.js +0 -176
  142. package/integrations/tests/use-cases/get-integrations-for-user.test.js +0 -176
  143. package/integrations/tests/use-cases/get-possible-integrations.test.js +0 -188
  144. package/integrations/tests/use-cases/update-integration-messages.test.js +0 -142
  145. package/integrations/tests/use-cases/update-integration-status.test.js +0 -103
  146. package/integrations/tests/use-cases/update-integration.test.js +0 -141
  147. package/integrations/use-cases/create-process.test.js +0 -178
  148. package/integrations/use-cases/get-process.test.js +0 -190
  149. package/integrations/use-cases/load-integration-context-full.test.js +0 -329
  150. package/integrations/use-cases/load-integration-context.test.js +0 -114
  151. package/integrations/use-cases/update-process-metrics.test.js +0 -308
  152. package/integrations/use-cases/update-process-state.test.js +0 -256
  153. package/lambda/TimeoutCatcher.test.js +0 -68
  154. package/logs/logger.test.js +0 -76
  155. package/modules/module-hydration.test.js +0 -205
  156. package/modules/requester/requester.test.js +0 -28
  157. package/user/tests/use-cases/create-individual-user.test.js +0 -24
  158. package/user/tests/use-cases/create-organization-user.test.js +0 -28
  159. package/user/tests/use-cases/create-token-for-user-id.test.js +0 -19
  160. package/user/tests/use-cases/get-user-from-bearer-token.test.js +0 -64
  161. package/user/tests/use-cases/login-user.test.js +0 -220
  162. package/user/tests/user-password-encryption-isolation.test.js +0 -237
  163. package/user/tests/user-password-hashing.test.js +0 -235
@@ -0,0 +1,363 @@
1
+
2
+ /* !!! This is code generated by Prisma. Do not edit directly. !!!
3
+ /* eslint-disable */
4
+
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+
7
+ const {
8
+ PrismaClientKnownRequestError,
9
+ PrismaClientUnknownRequestError,
10
+ PrismaClientRustPanicError,
11
+ PrismaClientInitializationError,
12
+ PrismaClientValidationError,
13
+ getPrismaClient,
14
+ sqltag,
15
+ empty,
16
+ join,
17
+ raw,
18
+ skip,
19
+ Decimal,
20
+ Debug,
21
+ objectEnumValues,
22
+ makeStrictEnum,
23
+ Extensions,
24
+ warnOnce,
25
+ defineDmmfProperty,
26
+ Public,
27
+ getRuntime,
28
+ createParam,
29
+ } = require('./runtime/wasm-engine-edge.js')
30
+
31
+
32
+ const Prisma = {}
33
+
34
+ exports.Prisma = Prisma
35
+ exports.$Enums = {}
36
+
37
+ /**
38
+ * Prisma Client JS version: 6.17.0
39
+ * Query Engine version: c0aafc03b8ef6cdced8654b9a817999e02457d6a
40
+ */
41
+ Prisma.prismaVersion = {
42
+ client: "6.17.0",
43
+ engine: "c0aafc03b8ef6cdced8654b9a817999e02457d6a"
44
+ }
45
+
46
+ Prisma.PrismaClientKnownRequestError = PrismaClientKnownRequestError;
47
+ Prisma.PrismaClientUnknownRequestError = PrismaClientUnknownRequestError
48
+ Prisma.PrismaClientRustPanicError = PrismaClientRustPanicError
49
+ Prisma.PrismaClientInitializationError = PrismaClientInitializationError
50
+ Prisma.PrismaClientValidationError = PrismaClientValidationError
51
+ Prisma.Decimal = Decimal
52
+
53
+ /**
54
+ * Re-export of sql-template-tag
55
+ */
56
+ Prisma.sql = sqltag
57
+ Prisma.empty = empty
58
+ Prisma.join = join
59
+ Prisma.raw = raw
60
+ Prisma.validator = Public.validator
61
+
62
+ /**
63
+ * Extensions
64
+ */
65
+ Prisma.getExtensionContext = Extensions.getExtensionContext
66
+ Prisma.defineExtension = Extensions.defineExtension
67
+
68
+ /**
69
+ * Shorthand utilities for JSON filtering
70
+ */
71
+ Prisma.DbNull = objectEnumValues.instances.DbNull
72
+ Prisma.JsonNull = objectEnumValues.instances.JsonNull
73
+ Prisma.AnyNull = objectEnumValues.instances.AnyNull
74
+
75
+ Prisma.NullTypes = {
76
+ DbNull: objectEnumValues.classes.DbNull,
77
+ JsonNull: objectEnumValues.classes.JsonNull,
78
+ AnyNull: objectEnumValues.classes.AnyNull
79
+ }
80
+
81
+
82
+
83
+
84
+
85
+ /**
86
+ * Enums
87
+ */
88
+ exports.Prisma.TransactionIsolationLevel = makeStrictEnum({
89
+ ReadUncommitted: 'ReadUncommitted',
90
+ ReadCommitted: 'ReadCommitted',
91
+ RepeatableRead: 'RepeatableRead',
92
+ Serializable: 'Serializable'
93
+ });
94
+
95
+ exports.Prisma.UserScalarFieldEnum = {
96
+ id: 'id',
97
+ type: 'type',
98
+ createdAt: 'createdAt',
99
+ updatedAt: 'updatedAt',
100
+ email: 'email',
101
+ username: 'username',
102
+ hashword: 'hashword',
103
+ appUserId: 'appUserId',
104
+ organizationId: 'organizationId',
105
+ appOrgId: 'appOrgId',
106
+ name: 'name'
107
+ };
108
+
109
+ exports.Prisma.TokenScalarFieldEnum = {
110
+ id: 'id',
111
+ token: 'token',
112
+ created: 'created',
113
+ expires: 'expires',
114
+ userId: 'userId'
115
+ };
116
+
117
+ exports.Prisma.CredentialScalarFieldEnum = {
118
+ id: 'id',
119
+ userId: 'userId',
120
+ authIsValid: 'authIsValid',
121
+ externalId: 'externalId',
122
+ data: 'data',
123
+ createdAt: 'createdAt',
124
+ updatedAt: 'updatedAt'
125
+ };
126
+
127
+ exports.Prisma.EntityScalarFieldEnum = {
128
+ id: 'id',
129
+ credentialId: 'credentialId',
130
+ userId: 'userId',
131
+ name: 'name',
132
+ moduleName: 'moduleName',
133
+ externalId: 'externalId',
134
+ createdAt: 'createdAt',
135
+ updatedAt: 'updatedAt'
136
+ };
137
+
138
+ exports.Prisma.IntegrationScalarFieldEnum = {
139
+ id: 'id',
140
+ userId: 'userId',
141
+ status: 'status',
142
+ config: 'config',
143
+ version: 'version',
144
+ errors: 'errors',
145
+ warnings: 'warnings',
146
+ info: 'info',
147
+ logs: 'logs',
148
+ createdAt: 'createdAt',
149
+ updatedAt: 'updatedAt'
150
+ };
151
+
152
+ exports.Prisma.IntegrationMappingScalarFieldEnum = {
153
+ id: 'id',
154
+ integrationId: 'integrationId',
155
+ sourceId: 'sourceId',
156
+ mapping: 'mapping',
157
+ createdAt: 'createdAt',
158
+ updatedAt: 'updatedAt'
159
+ };
160
+
161
+ exports.Prisma.SyncScalarFieldEnum = {
162
+ id: 'id',
163
+ integrationId: 'integrationId',
164
+ hash: 'hash',
165
+ name: 'name'
166
+ };
167
+
168
+ exports.Prisma.DataIdentifierScalarFieldEnum = {
169
+ id: 'id',
170
+ syncId: 'syncId',
171
+ entityId: 'entityId',
172
+ idData: 'idData',
173
+ hash: 'hash'
174
+ };
175
+
176
+ exports.Prisma.AssociationScalarFieldEnum = {
177
+ id: 'id',
178
+ integrationId: 'integrationId',
179
+ name: 'name',
180
+ type: 'type',
181
+ primaryObject: 'primaryObject'
182
+ };
183
+
184
+ exports.Prisma.AssociationObjectScalarFieldEnum = {
185
+ id: 'id',
186
+ associationId: 'associationId',
187
+ entityId: 'entityId',
188
+ objectType: 'objectType',
189
+ objId: 'objId',
190
+ metadata: 'metadata'
191
+ };
192
+
193
+ exports.Prisma.ProcessScalarFieldEnum = {
194
+ id: 'id',
195
+ userId: 'userId',
196
+ integrationId: 'integrationId',
197
+ name: 'name',
198
+ type: 'type',
199
+ state: 'state',
200
+ context: 'context',
201
+ results: 'results',
202
+ parentProcessId: 'parentProcessId',
203
+ createdAt: 'createdAt',
204
+ updatedAt: 'updatedAt'
205
+ };
206
+
207
+ exports.Prisma.StateScalarFieldEnum = {
208
+ id: 'id',
209
+ state: 'state'
210
+ };
211
+
212
+ exports.Prisma.WebsocketConnectionScalarFieldEnum = {
213
+ id: 'id',
214
+ connectionId: 'connectionId'
215
+ };
216
+
217
+ exports.Prisma.SortOrder = {
218
+ asc: 'asc',
219
+ desc: 'desc'
220
+ };
221
+
222
+ exports.Prisma.JsonNullValueInput = {
223
+ JsonNull: Prisma.JsonNull
224
+ };
225
+
226
+ exports.Prisma.NullableJsonNullValueInput = {
227
+ DbNull: Prisma.DbNull,
228
+ JsonNull: Prisma.JsonNull
229
+ };
230
+
231
+ exports.Prisma.QueryMode = {
232
+ default: 'default',
233
+ insensitive: 'insensitive'
234
+ };
235
+
236
+ exports.Prisma.NullsOrder = {
237
+ first: 'first',
238
+ last: 'last'
239
+ };
240
+
241
+ exports.Prisma.JsonNullValueFilter = {
242
+ DbNull: Prisma.DbNull,
243
+ JsonNull: Prisma.JsonNull,
244
+ AnyNull: Prisma.AnyNull
245
+ };
246
+ exports.UserType = exports.$Enums.UserType = {
247
+ INDIVIDUAL: 'INDIVIDUAL',
248
+ ORGANIZATION: 'ORGANIZATION'
249
+ };
250
+
251
+ exports.IntegrationStatus = exports.$Enums.IntegrationStatus = {
252
+ ENABLED: 'ENABLED',
253
+ NEEDS_CONFIG: 'NEEDS_CONFIG',
254
+ PROCESSING: 'PROCESSING',
255
+ DISABLED: 'DISABLED',
256
+ ERROR: 'ERROR'
257
+ };
258
+
259
+ exports.AssociationType = exports.$Enums.AssociationType = {
260
+ ONE_TO_MANY: 'ONE_TO_MANY',
261
+ ONE_TO_ONE: 'ONE_TO_ONE',
262
+ MANY_TO_ONE: 'MANY_TO_ONE'
263
+ };
264
+
265
+ exports.Prisma.ModelName = {
266
+ User: 'User',
267
+ Token: 'Token',
268
+ Credential: 'Credential',
269
+ Entity: 'Entity',
270
+ Integration: 'Integration',
271
+ IntegrationMapping: 'IntegrationMapping',
272
+ Sync: 'Sync',
273
+ DataIdentifier: 'DataIdentifier',
274
+ Association: 'Association',
275
+ AssociationObject: 'AssociationObject',
276
+ Process: 'Process',
277
+ State: 'State',
278
+ WebsocketConnection: 'WebsocketConnection'
279
+ };
280
+ /**
281
+ * Create the Client
282
+ */
283
+ const config = {
284
+ "generator": {
285
+ "name": "client",
286
+ "provider": {
287
+ "fromEnvVar": null,
288
+ "value": "prisma-client-js"
289
+ },
290
+ "output": {
291
+ "value": "/home/runner/work/frigg/frigg/packages/core/generated/prisma-postgresql",
292
+ "fromEnvVar": null
293
+ },
294
+ "config": {
295
+ "engineType": "binary"
296
+ },
297
+ "binaryTargets": [
298
+ {
299
+ "fromEnvVar": null,
300
+ "value": "debian-openssl-3.0.x",
301
+ "native": true
302
+ },
303
+ {
304
+ "fromEnvVar": null,
305
+ "value": "rhel-openssl-3.0.x"
306
+ }
307
+ ],
308
+ "previewFeatures": [],
309
+ "sourceFilePath": "/home/runner/work/frigg/frigg/packages/core/prisma-postgresql/schema.prisma",
310
+ "isCustomOutput": true
311
+ },
312
+ "relativeEnvPaths": {
313
+ "rootEnvPath": null
314
+ },
315
+ "relativePath": "../../prisma-postgresql",
316
+ "clientVersion": "6.17.0",
317
+ "engineVersion": "c0aafc03b8ef6cdced8654b9a817999e02457d6a",
318
+ "datasourceNames": [
319
+ "db"
320
+ ],
321
+ "activeProvider": "postgresql",
322
+ "postinstall": false,
323
+ "ciName": "GitHub Actions",
324
+ "inlineDatasources": {
325
+ "db": {
326
+ "url": {
327
+ "fromEnvVar": "DATABASE_URL",
328
+ "value": null
329
+ }
330
+ }
331
+ },
332
+ "inlineSchema": "// Frigg Framework - Prisma Schema (PostgreSQL)\n// PostgreSQL database schema for enterprise integration platform\n// Converted from MongoDB schema for relational database support\n\ngenerator client {\n provider = \"prisma-client-js\"\n output = \"../generated/prisma-postgresql\"\n binaryTargets = [\"native\", \"rhel-openssl-3.0.x\"] // native for local dev, rhel for Lambda deployment\n engineType = \"binary\" // Use binary engines (smaller size)\n}\n\ndatasource db {\n provider = \"postgresql\"\n url = env(\"DATABASE_URL\")\n}\n\n// ============================================================================\n// USER MODELS\n// ============================================================================\n\n/// User model with discriminator pattern support\n/// Replaces Mongoose discriminators (IndividualUser, OrganizationUser)\nmodel User {\n id Int @id @default(autoincrement())\n type UserType\n\n // Timestamps\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n // IndividualUser fields (nullable for organizations)\n email String?\n username String?\n hashword String? // Bcrypt hashed password (handled in application layer)\n appUserId String?\n organizationId Int?\n\n // Self-referential relation for organization membership\n organization User? @relation(\"OrgMembers\", fields: [organizationId], references: [id], onDelete: NoAction, onUpdate: NoAction)\n members User[] @relation(\"OrgMembers\")\n\n // OrganizationUser fields (nullable for individuals)\n appOrgId String?\n name String?\n\n // Relations\n tokens Token[]\n credentials Credential[]\n entities Entity[]\n integrations Integration[]\n processes Process[]\n\n @@unique([email])\n @@unique([username])\n @@unique([appOrgId])\n @@index([type])\n @@index([appUserId])\n}\n\nenum UserType {\n INDIVIDUAL\n ORGANIZATION\n}\n\n// ============================================================================\n// AUTHENTICATION MODELS\n// ============================================================================\n\n/// Authentication tokens with expiration\n/// Bcrypt hashed tokens stored (handled in application layer)\nmodel Token {\n id Int @id @default(autoincrement())\n token String // Bcrypt hashed\n created DateTime @default(now())\n expires DateTime?\n userId Int\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@index([userId])\n @@index([expires])\n}\n\n// ============================================================================\n// CREDENTIAL & ENTITY MODELS\n// ============================================================================\n\n/// OAuth credentials and API tokens\n/// All sensitive data encrypted with KMS at rest\nmodel Credential {\n id Int @id @default(autoincrement())\n userId Int?\n user User? @relation(fields: [userId], references: [id], onDelete: Cascade)\n authIsValid Boolean?\n externalId String?\n\n // Dynamic OAuth fields stored as JSON (encrypted via Prisma middleware)\n // Contains: access_token, refresh_token, domain, expires_in, token_type, etc.\n data Json @default(\"{}\")\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n // Relations\n entities Entity[]\n\n @@index([userId])\n @@index([externalId])\n}\n\n/// External service entities (API connections)\nmodel Entity {\n id Int @id @default(autoincrement())\n credentialId Int?\n credential Credential? @relation(fields: [credentialId], references: [id], onDelete: SetNull)\n userId Int?\n user User? @relation(fields: [userId], references: [id], onDelete: Cascade)\n name String?\n moduleName String?\n externalId String?\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n // Relations - many-to-many with implicit join tables\n integrations Integration[]\n syncs Sync[]\n\n dataIdentifiers DataIdentifier[]\n associationObjects AssociationObject[]\n\n @@index([userId])\n @@index([externalId])\n @@index([moduleName])\n @@index([credentialId])\n}\n\n// ============================================================================\n// INTEGRATION MODELS\n// ============================================================================\n\n/// Main integration configuration and state\nmodel Integration {\n id Int @id @default(autoincrement())\n userId Int?\n user User? @relation(fields: [userId], references: [id], onDelete: Cascade)\n status IntegrationStatus @default(ENABLED)\n\n // Configuration and version\n config Json? // Integration configuration object\n version String?\n\n // Entity references (many-to-many via implicit join table)\n entities Entity[]\n\n // Message arrays (stored as JSON)\n errors Json @default(\"[]\")\n warnings Json @default(\"[]\")\n info Json @default(\"[]\")\n logs Json @default(\"[]\")\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n // Relations\n associations Association[]\n syncs Sync[]\n mappings IntegrationMapping[]\n processes Process[]\n\n @@index([userId])\n @@index([status])\n}\n\nenum IntegrationStatus {\n ENABLED\n NEEDS_CONFIG\n PROCESSING\n DISABLED\n ERROR\n}\n\n/// Integration-specific data mappings\n/// All mapping data encrypted with KMS\nmodel IntegrationMapping {\n id Int @id @default(autoincrement())\n integrationId Int\n integration Integration @relation(fields: [integrationId], references: [id], onDelete: Cascade)\n sourceId String?\n\n // Encrypted mapping data (handled via Prisma middleware)\n mapping Json?\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n @@unique([integrationId, sourceId])\n @@index([integrationId])\n @@index([sourceId])\n}\n\n// ============================================================================\n// SYNC MODELS\n// ============================================================================\n\n/// Bidirectional data synchronization tracking\nmodel Sync {\n id Int @id @default(autoincrement())\n integrationId Int?\n integration Integration? @relation(fields: [integrationId], references: [id], onDelete: Cascade)\n\n // Entity references (many-to-many via implicit join table)\n entities Entity[]\n\n hash String\n name String\n\n // Data identifiers (extracted to separate model)\n dataIdentifiers DataIdentifier[]\n\n @@index([integrationId])\n @@index([hash])\n @@index([name])\n}\n\n/// Data identifier for sync operations\n/// Replaces nested array structure in Mongoose\nmodel DataIdentifier {\n id Int @id @default(autoincrement())\n syncId Int?\n sync Sync? @relation(fields: [syncId], references: [id], onDelete: Cascade)\n entityId Int\n entity Entity @relation(fields: [entityId], references: [id], onDelete: Cascade)\n\n // Identifier data (can be any structure)\n idData Json\n\n hash String\n\n @@index([syncId])\n @@index([entityId])\n @@index([hash])\n}\n\n// ============================================================================\n// ASSOCIATION MODELS\n// ============================================================================\n\n/// Entity associations with cardinality tracking\nmodel Association {\n id Int @id @default(autoincrement())\n integrationId Int\n integration Integration @relation(fields: [integrationId], references: [id], onDelete: Cascade)\n name String\n type AssociationType\n primaryObject String\n\n // Associated objects (extracted to separate model)\n objects AssociationObject[]\n\n @@index([integrationId])\n @@index([name])\n}\n\n/// Association object entry\n/// Replaces nested array structure in Mongoose\nmodel AssociationObject {\n id Int @id @default(autoincrement())\n associationId Int\n association Association @relation(fields: [associationId], references: [id], onDelete: Cascade)\n entityId Int\n entity Entity @relation(fields: [entityId], references: [id], onDelete: Cascade)\n objectType String\n objId String\n metadata Json? // Optional metadata\n\n @@index([associationId])\n @@index([entityId])\n}\n\nenum AssociationType {\n ONE_TO_MANY\n ONE_TO_ONE\n MANY_TO_ONE\n}\n\n// ============================================================================\n// PROCESS MODELS\n// ============================================================================\n\n/// Generic Process Model - tracks any long-running operation\n/// Used for: CRM syncs, data migrations, bulk operations, etc.\nmodel Process {\n id Int @id @default(autoincrement())\n\n // Core references\n userId Int\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n integrationId Int\n integration Integration @relation(fields: [integrationId], references: [id], onDelete: Cascade)\n\n // Process identification\n name String // e.g., \"zoho-crm-contact-sync\", \"pipedrive-lead-sync\"\n type String // e.g., \"CRM_SYNC\", \"DATA_MIGRATION\", \"BULK_OPERATION\"\n\n // State machine\n state String // Current state (integration-defined states)\n\n // Flexible storage\n context Json @default(\"{}\") // Process-specific data (pagination, metadata, etc.)\n results Json @default(\"{}\") // Process results and metrics\n\n // Hierarchy support - self-referential relation\n parentProcessId Int?\n parentProcess Process? @relation(\"ProcessHierarchy\", fields: [parentProcessId], references: [id], onDelete: SetNull)\n childProcesses Process[] @relation(\"ProcessHierarchy\")\n\n // Timestamps\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n @@index([userId])\n @@index([integrationId])\n @@index([type])\n @@index([state])\n @@index([name])\n @@index([parentProcessId])\n}\n\n// ============================================================================\n// UTILITY MODELS\n// ============================================================================\n\n/// Generic state storage\nmodel State {\n id Int @id @default(autoincrement())\n state Json?\n}\n\n/// AWS API Gateway WebSocket connection tracking\nmodel WebsocketConnection {\n id Int @id @default(autoincrement())\n connectionId String?\n\n @@index([connectionId])\n}\n",
333
+ "inlineSchemaHash": "14f51350fa721bf361ac1d9586fde3cf2e3b31009007a875ab4e7143f59012e6",
334
+ "copyEngine": true
335
+ }
336
+ config.dirname = '/'
337
+
338
+ config.runtimeDataModel = JSON.parse("{\"models\":{\"User\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"type\",\"kind\":\"enum\",\"type\":\"UserType\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"email\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"username\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"hashword\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"appUserId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"organizationId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"organization\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"OrgMembers\"},{\"name\":\"members\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"OrgMembers\"},{\"name\":\"appOrgId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"tokens\",\"kind\":\"object\",\"type\":\"Token\",\"relationName\":\"TokenToUser\"},{\"name\":\"credentials\",\"kind\":\"object\",\"type\":\"Credential\",\"relationName\":\"CredentialToUser\"},{\"name\":\"entities\",\"kind\":\"object\",\"type\":\"Entity\",\"relationName\":\"EntityToUser\"},{\"name\":\"integrations\",\"kind\":\"object\",\"type\":\"Integration\",\"relationName\":\"IntegrationToUser\"},{\"name\":\"processes\",\"kind\":\"object\",\"type\":\"Process\",\"relationName\":\"ProcessToUser\"}],\"dbName\":null},\"Token\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"token\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"created\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"expires\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"TokenToUser\"}],\"dbName\":null},\"Credential\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"CredentialToUser\"},{\"name\":\"authIsValid\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"externalId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"data\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"entities\",\"kind\":\"object\",\"type\":\"Entity\",\"relationName\":\"CredentialToEntity\"}],\"dbName\":null},\"Entity\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"credentialId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"credential\",\"kind\":\"object\",\"type\":\"Credential\",\"relationName\":\"CredentialToEntity\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"EntityToUser\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"moduleName\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"externalId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"integrations\",\"kind\":\"object\",\"type\":\"Integration\",\"relationName\":\"EntityToIntegration\"},{\"name\":\"syncs\",\"kind\":\"object\",\"type\":\"Sync\",\"relationName\":\"EntityToSync\"},{\"name\":\"dataIdentifiers\",\"kind\":\"object\",\"type\":\"DataIdentifier\",\"relationName\":\"DataIdentifierToEntity\"},{\"name\":\"associationObjects\",\"kind\":\"object\",\"type\":\"AssociationObject\",\"relationName\":\"AssociationObjectToEntity\"}],\"dbName\":null},\"Integration\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"IntegrationToUser\"},{\"name\":\"status\",\"kind\":\"enum\",\"type\":\"IntegrationStatus\"},{\"name\":\"config\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"version\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"entities\",\"kind\":\"object\",\"type\":\"Entity\",\"relationName\":\"EntityToIntegration\"},{\"name\":\"errors\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"warnings\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"info\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"logs\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"associations\",\"kind\":\"object\",\"type\":\"Association\",\"relationName\":\"AssociationToIntegration\"},{\"name\":\"syncs\",\"kind\":\"object\",\"type\":\"Sync\",\"relationName\":\"IntegrationToSync\"},{\"name\":\"mappings\",\"kind\":\"object\",\"type\":\"IntegrationMapping\",\"relationName\":\"IntegrationToIntegrationMapping\"},{\"name\":\"processes\",\"kind\":\"object\",\"type\":\"Process\",\"relationName\":\"IntegrationToProcess\"}],\"dbName\":null},\"IntegrationMapping\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"integrationId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"integration\",\"kind\":\"object\",\"type\":\"Integration\",\"relationName\":\"IntegrationToIntegrationMapping\"},{\"name\":\"sourceId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"mapping\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"Sync\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"integrationId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"integration\",\"kind\":\"object\",\"type\":\"Integration\",\"relationName\":\"IntegrationToSync\"},{\"name\":\"entities\",\"kind\":\"object\",\"type\":\"Entity\",\"relationName\":\"EntityToSync\"},{\"name\":\"hash\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"dataIdentifiers\",\"kind\":\"object\",\"type\":\"DataIdentifier\",\"relationName\":\"DataIdentifierToSync\"}],\"dbName\":null},\"DataIdentifier\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"syncId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"sync\",\"kind\":\"object\",\"type\":\"Sync\",\"relationName\":\"DataIdentifierToSync\"},{\"name\":\"entityId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"entity\",\"kind\":\"object\",\"type\":\"Entity\",\"relationName\":\"DataIdentifierToEntity\"},{\"name\":\"idData\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"hash\",\"kind\":\"scalar\",\"type\":\"String\"}],\"dbName\":null},\"Association\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"integrationId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"integration\",\"kind\":\"object\",\"type\":\"Integration\",\"relationName\":\"AssociationToIntegration\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"type\",\"kind\":\"enum\",\"type\":\"AssociationType\"},{\"name\":\"primaryObject\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"objects\",\"kind\":\"object\",\"type\":\"AssociationObject\",\"relationName\":\"AssociationToAssociationObject\"}],\"dbName\":null},\"AssociationObject\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"associationId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"association\",\"kind\":\"object\",\"type\":\"Association\",\"relationName\":\"AssociationToAssociationObject\"},{\"name\":\"entityId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"entity\",\"kind\":\"object\",\"type\":\"Entity\",\"relationName\":\"AssociationObjectToEntity\"},{\"name\":\"objectType\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"objId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"metadata\",\"kind\":\"scalar\",\"type\":\"Json\"}],\"dbName\":null},\"Process\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"ProcessToUser\"},{\"name\":\"integrationId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"integration\",\"kind\":\"object\",\"type\":\"Integration\",\"relationName\":\"IntegrationToProcess\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"type\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"state\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"context\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"results\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"parentProcessId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"parentProcess\",\"kind\":\"object\",\"type\":\"Process\",\"relationName\":\"ProcessHierarchy\"},{\"name\":\"childProcesses\",\"kind\":\"object\",\"type\":\"Process\",\"relationName\":\"ProcessHierarchy\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"State\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"state\",\"kind\":\"scalar\",\"type\":\"Json\"}],\"dbName\":null},\"WebsocketConnection\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"connectionId\",\"kind\":\"scalar\",\"type\":\"String\"}],\"dbName\":null}},\"enums\":{},\"types\":{}}")
339
+ defineDmmfProperty(exports.Prisma, config.runtimeDataModel)
340
+ config.engineWasm = {
341
+ getRuntime: async () => require('./query_engine_bg.js'),
342
+ getQueryEngineWasmModule: async () => {
343
+ const loader = (await import('#wasm-engine-loader')).default
344
+ const engine = (await loader).default
345
+ return engine
346
+ }
347
+ }
348
+ config.compilerWasm = undefined
349
+
350
+ config.injectableEdgeEnv = () => ({
351
+ parsed: {
352
+ DATABASE_URL: typeof globalThis !== 'undefined' && globalThis['DATABASE_URL'] || typeof process !== 'undefined' && process.env && process.env.DATABASE_URL || undefined
353
+ }
354
+ })
355
+
356
+ if (typeof globalThis !== 'undefined' && globalThis['DEBUG'] || typeof process !== 'undefined' && process.env && process.env.DEBUG || undefined) {
357
+ Debug.enable(typeof globalThis !== 'undefined' && globalThis['DEBUG'] || typeof process !== 'undefined' && process.env && process.env.DEBUG || undefined)
358
+ }
359
+
360
+ const PrismaClient = getPrismaClient(config)
361
+ exports.PrismaClient = PrismaClient
362
+ Object.assign(exports, Prisma)
363
+
@@ -0,0 +1,227 @@
1
+ /**
2
+ * Database Migration Handler for AWS Lambda
3
+ *
4
+ * Executes Prisma migrations in a Lambda environment.
5
+ * Based on AWS best practices for running migrations in serverless environments.
6
+ *
7
+ * Supported Commands:
8
+ * - deploy: Apply pending migrations to the database (production-safe)
9
+ * - reset: Reset database and apply all migrations (DANGEROUS - dev only)
10
+ *
11
+ * Usage:
12
+ * // Via Lambda invoke
13
+ * {
14
+ * "command": "deploy" // or "reset"
15
+ * }
16
+ *
17
+ * Requirements:
18
+ * - Prisma CLI must be included in deployment or Lambda layer
19
+ * - DATABASE_URL environment variable must be set
20
+ * - VPC configuration for Aurora access
21
+ *
22
+ * Reference: https://www.prisma.io/docs/guides/deployment/deployment-guides/deploying-to-aws-lambda
23
+ */
24
+
25
+ const { execFile } = require('child_process');
26
+ const path = require('path');
27
+
28
+ /**
29
+ * Execute Prisma migration command
30
+ *
31
+ * @param {string} command - Migration command ('deploy' or 'reset')
32
+ * @param {string} schemaPath - Path to Prisma schema file
33
+ * @returns {Promise<number>} Exit code
34
+ */
35
+ async function executePrismaMigration(command, schemaPath) {
36
+ console.log(`Executing Prisma migration: ${command}`);
37
+ console.log(`Schema path: ${schemaPath}`);
38
+ console.log(`Database URL: ${process.env.DATABASE_URL ? '[SET]' : '[NOT SET]'}`);
39
+
40
+ return new Promise((resolve, reject) => {
41
+ // Build command arguments
42
+ const args = ['migrate', command];
43
+
44
+ // Add command-specific options
45
+ if (command === 'reset') {
46
+ args.push('--force'); // Skip confirmation prompt
47
+ args.push('--skip-generate'); // Skip client generation (already done in layer)
48
+ }
49
+
50
+ // Add schema path if provided
51
+ if (schemaPath) {
52
+ args.push('--schema', schemaPath);
53
+ }
54
+
55
+ console.log(`Running: prisma ${args.join(' ')}`);
56
+
57
+ // Execute Prisma CLI
58
+ execFile(
59
+ path.resolve('./node_modules/prisma/build/index.js'),
60
+ args,
61
+ {
62
+ env: {
63
+ ...process.env,
64
+ // Ensure Prisma uses the correct binary target
65
+ PRISMA_CLI_BINARY_TARGETS: 'rhel-openssl-3.0.x',
66
+ }
67
+ },
68
+ (error, stdout, stderr) => {
69
+ // Log all output
70
+ if (stdout) {
71
+ console.log('STDOUT:', stdout);
72
+ }
73
+ if (stderr) {
74
+ console.error('STDERR:', stderr);
75
+ }
76
+
77
+ if (error) {
78
+ console.error(`Migration ${command} exited with error:`, error.message);
79
+ console.error(`Exit code: ${error.code || 1}`);
80
+ resolve(error.code || 1);
81
+ } else {
82
+ console.log(`Migration ${command} completed successfully`);
83
+ resolve(0);
84
+ }
85
+ }
86
+ );
87
+ });
88
+ }
89
+
90
+ /**
91
+ * Validate migration command
92
+ */
93
+ function validateCommand(command) {
94
+ const validCommands = ['deploy', 'reset'];
95
+
96
+ if (!validCommands.includes(command)) {
97
+ throw new Error(
98
+ `Invalid migration command: "${command}". ` +
99
+ `Valid commands are: ${validCommands.join(', ')}`
100
+ );
101
+ }
102
+
103
+ // Extra validation for dangerous commands
104
+ if (command === 'reset') {
105
+ const stage = process.env.STAGE || process.env.NODE_ENV;
106
+ if (stage === 'production' || stage === 'prod') {
107
+ throw new Error(
108
+ 'BLOCKED: "reset" command is not allowed in production environment. ' +
109
+ 'This command would delete all data. Use "deploy" instead.'
110
+ );
111
+ }
112
+ console.warn('⚠️ WARNING: "reset" will DELETE all data and reset the database!');
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Determine which Prisma schema to use based on database type
118
+ */
119
+ function getSchemaPath() {
120
+ // In Lambda, schemas are in @friggframework/core/generated/
121
+ const baseSchemaPath = './node_modules/@friggframework/core/generated';
122
+
123
+ // Check if Postgres is enabled
124
+ if (process.env.DATABASE_URL?.includes('postgresql') || process.env.DATABASE_URL?.includes('postgres')) {
125
+ const schemaPath = `${baseSchemaPath}/prisma-postgresql/schema.prisma`;
126
+ console.log(`Using PostgreSQL schema: ${schemaPath}`);
127
+ return schemaPath;
128
+ }
129
+
130
+ // Check if MongoDB is enabled
131
+ if (process.env.DATABASE_URL?.includes('mongodb')) {
132
+ const schemaPath = `${baseSchemaPath}/prisma-mongodb/schema.prisma`;
133
+ console.log(`Using MongoDB schema: ${schemaPath}`);
134
+ return schemaPath;
135
+ }
136
+
137
+ // Default to PostgreSQL
138
+ console.log('DATABASE_URL not set or database type unknown, defaulting to PostgreSQL');
139
+ return `${baseSchemaPath}/prisma-postgresql/schema.prisma`;
140
+ }
141
+
142
+ /**
143
+ * Lambda handler for database migrations
144
+ *
145
+ * @param {Object} event - Lambda event
146
+ * @param {string} event.command - Migration command ('deploy' or 'reset')
147
+ * @param {Object} context - Lambda context
148
+ * @returns {Promise<Object>} Migration result
149
+ */
150
+ exports.handler = async (event, context) => {
151
+ const startTime = Date.now();
152
+
153
+ console.log('='.repeat(60));
154
+ console.log('Database Migration Handler');
155
+ console.log('='.repeat(60));
156
+ console.log('Event:', JSON.stringify(event, null, 2));
157
+ console.log('Context:', JSON.stringify({
158
+ functionName: context.functionName,
159
+ functionVersion: context.functionVersion,
160
+ memoryLimitInMB: context.memoryLimitInMB,
161
+ logGroupName: context.logGroupName,
162
+ }, null, 2));
163
+
164
+ try {
165
+ // Get migration command (default to 'deploy')
166
+ const command = event.command || 'deploy';
167
+
168
+ // Validate command
169
+ validateCommand(command);
170
+
171
+ // Check required environment variables
172
+ if (!process.env.DATABASE_URL) {
173
+ throw new Error(
174
+ 'DATABASE_URL environment variable is not set. ' +
175
+ 'Cannot connect to database for migrations.'
176
+ );
177
+ }
178
+
179
+ // Determine schema path
180
+ const schemaPath = getSchemaPath();
181
+
182
+ // Execute migration
183
+ const exitCode = await executePrismaMigration(command, schemaPath);
184
+
185
+ const duration = Date.now() - startTime;
186
+
187
+ if (exitCode === 0) {
188
+ const result = {
189
+ success: true,
190
+ command,
191
+ message: `Migration ${command} completed successfully`,
192
+ duration: `${duration}ms`,
193
+ timestamp: new Date().toISOString(),
194
+ };
195
+
196
+ console.log('='.repeat(60));
197
+ console.log('Migration completed successfully');
198
+ console.log(JSON.stringify(result, null, 2));
199
+ console.log('='.repeat(60));
200
+
201
+ return result;
202
+ } else {
203
+ throw new Error(`Migration ${command} failed with exit code ${exitCode}`);
204
+ }
205
+
206
+ } catch (error) {
207
+ const duration = Date.now() - startTime;
208
+
209
+ console.error('='.repeat(60));
210
+ console.error('Migration failed');
211
+ console.error('Error:', error.message);
212
+ console.error('Stack:', error.stack);
213
+ console.error('='.repeat(60));
214
+
215
+ const errorResult = {
216
+ success: false,
217
+ command: event.command || 'unknown',
218
+ error: error.message,
219
+ duration: `${duration}ms`,
220
+ timestamp: new Date().toISOString(),
221
+ };
222
+
223
+ // Return error (don't throw) so Lambda doesn't retry
224
+ return errorResult;
225
+ }
226
+ };
227
+
@@ -3,7 +3,7 @@ const { createAppHandler } = require('./../app-handler-helpers');
3
3
 
4
4
  const router = createIntegrationRouter();
5
5
 
6
- router.route('/redirect/:appId').get((req, res) => {
6
+ router.route('/api/integrations/redirect/:appId').get((req, res) => {
7
7
  res.redirect(
8
8
  `${process.env.FRONTEND_URI}/redirect/${req.params.appId
9
9
  }?${new URLSearchParams(req.query)}`
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Database Migration Router Lambda Handler
3
+ *
4
+ * Minimal Lambda wrapper that avoids loading core/index.js
5
+ * (which would try to load user/** modules excluded from migration packages)
6
+ *
7
+ * This handler is intentionally simpler than health.handler.js to avoid dependencies.
8
+ */
9
+
10
+ const serverlessHttp = require('serverless-http');
11
+ const express = require('express');
12
+ const cors = require('cors');
13
+ const dbMigrationRouter = require('./db-migration');
14
+
15
+ // Create minimal Express app
16
+ const app = express();
17
+ app.use(cors());
18
+ app.use(express.json());
19
+ app.use(dbMigrationRouter);
20
+
21
+ // Error handler
22
+ app.use((err, req, res, next) => {
23
+ console.error('Error:', err);
24
+ res.status(500).json({ message: 'Internal Server Error' });
25
+ });
26
+
27
+ // Export as .handler property (Lambda config: db-migration.handler)
28
+ module.exports.handler = serverlessHttp(app);
29
+