@friggframework/core 2.0.0--canary.496.a94ee46.0 → 2.0.0--canary.490.feacde9.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 (51) hide show
  1. package/core/create-handler.js +63 -12
  2. package/database/PRISMA_BEST_PRACTICES.md +654 -0
  3. package/database/index.js +7 -29
  4. package/database/prisma.js +51 -19
  5. package/database/repositories/health-check-repository-mongodb.js +18 -22
  6. package/database/utils/mongodb-collection-utils.js +26 -18
  7. package/database/utils/mongodb-schema-init.js +7 -12
  8. package/generated/prisma-mongodb/edge.js +6 -6
  9. package/generated/prisma-mongodb/index-browser.js +4 -4
  10. package/generated/prisma-mongodb/index.d.ts +3 -2
  11. package/generated/prisma-mongodb/index.js +6 -6
  12. package/generated/prisma-mongodb/package.json +1 -1
  13. package/generated/prisma-mongodb/query-engine-debian-openssl-3.0.x +0 -0
  14. package/generated/prisma-mongodb/query-engine-rhel-openssl-3.0.x +0 -0
  15. package/generated/prisma-mongodb/runtime/binary.js +2 -2
  16. package/generated/prisma-mongodb/runtime/edge-esm.js +3 -3
  17. package/generated/prisma-mongodb/runtime/edge.js +3 -3
  18. package/generated/prisma-mongodb/runtime/library.d.ts +5 -0
  19. package/generated/prisma-mongodb/runtime/react-native.js +14 -14
  20. package/generated/prisma-mongodb/runtime/wasm-compiler-edge.js +18 -18
  21. package/generated/prisma-mongodb/runtime/wasm-engine-edge.js +11 -11
  22. package/generated/prisma-mongodb/wasm.js +6 -6
  23. package/generated/prisma-postgresql/edge.js +6 -6
  24. package/generated/prisma-postgresql/index-browser.js +4 -4
  25. package/generated/prisma-postgresql/index.d.ts +3 -2
  26. package/generated/prisma-postgresql/index.js +6 -6
  27. package/generated/prisma-postgresql/package.json +1 -1
  28. package/generated/prisma-postgresql/query-engine-debian-openssl-3.0.x +0 -0
  29. package/generated/prisma-postgresql/query-engine-rhel-openssl-3.0.x +0 -0
  30. package/generated/prisma-postgresql/query_engine_bg.js +2 -2
  31. package/generated/prisma-postgresql/query_engine_bg.wasm +0 -0
  32. package/generated/prisma-postgresql/runtime/binary.js +2 -2
  33. package/generated/prisma-postgresql/runtime/edge-esm.js +3 -3
  34. package/generated/prisma-postgresql/runtime/edge.js +3 -3
  35. package/generated/prisma-postgresql/runtime/library.d.ts +5 -0
  36. package/generated/prisma-postgresql/runtime/react-native.js +14 -14
  37. package/generated/prisma-postgresql/runtime/wasm-compiler-edge.js +18 -18
  38. package/generated/prisma-postgresql/runtime/wasm-engine-edge.js +11 -11
  39. package/generated/prisma-postgresql/wasm.js +6 -6
  40. package/integrations/integration-router.js +0 -1
  41. package/integrations/use-cases/delete-integration-for-user.js +3 -31
  42. package/integrations/use-cases/get-integrations-for-user.js +4 -5
  43. package/integrations/utils/map-integration-dto.js +1 -2
  44. package/modules/index.js +0 -2
  45. package/package.json +5 -5
  46. package/associations/model.js +0 -54
  47. package/database/models/UserModel.js +0 -7
  48. package/database/models/WebsocketConnection.js +0 -55
  49. package/database/repositories/health-check-repository.js +0 -108
  50. package/modules/entity.js +0 -46
  51. package/syncs/model.js +0 -62
@@ -14,22 +14,40 @@ const config = require('./config');
14
14
  * Note: This should only be called when DB_TYPE is 'mongodb'
15
15
  */
16
16
  function ensureMongoDbUrl() {
17
- // If DATABASE_URL is already set, use it
17
+ let connectionString;
18
+
18
19
  if (process.env.DATABASE_URL && process.env.DATABASE_URL.trim()) {
19
- return;
20
- }
21
-
22
- // Fallback to MONGO_URI for backwards compatibility with DocumentDB deployments
23
- if (process.env.MONGO_URI && process.env.MONGO_URI.trim()) {
24
- process.env.DATABASE_URL = process.env.MONGO_URI;
20
+ connectionString = process.env.DATABASE_URL;
21
+ } else if (process.env.MONGO_URI && process.env.MONGO_URI.trim()) {
22
+ connectionString = process.env.MONGO_URI;
25
23
  logger.debug('Using MONGO_URI as DATABASE_URL for MongoDB connection');
26
- return;
24
+ } else {
25
+ throw new Error(
26
+ 'DATABASE_URL or MONGO_URI environment variable must be set for MongoDB'
27
+ );
27
28
  }
28
-
29
- // Neither is set - error
30
- throw new Error(
31
- 'DATABASE_URL or MONGO_URI environment variable must be set for MongoDB'
32
- );
29
+
30
+ // Ensure readPreference=primary for transaction support
31
+ // MongoDB requires this for all operations within transactions
32
+ try {
33
+ const url = new URL(connectionString);
34
+ const params = url.searchParams;
35
+
36
+ const existingReadPreference = params.get('readPreference');
37
+ if (existingReadPreference && existingReadPreference !== 'primary') {
38
+ params.set('readPreference', 'primary');
39
+ logger.debug(`Overrode readPreference from ${existingReadPreference} to primary for transaction support`);
40
+ } else if (!existingReadPreference) {
41
+ params.set('readPreference', 'primary');
42
+ logger.debug('Added readPreference=primary to MongoDB connection string for transaction support');
43
+ }
44
+
45
+ connectionString = url.toString();
46
+ } catch (error) {
47
+ logger.warn('Failed to parse MongoDB connection string as URL, skipping readPreference configuration:', error.message);
48
+ }
49
+
50
+ process.env.DATABASE_URL = connectionString;
33
51
  }
34
52
 
35
53
  function getEncryptionConfig() {
@@ -104,14 +122,27 @@ const prismaClientSingleton = () => {
104
122
 
105
123
  // Helper to try loading Prisma client from multiple locations
106
124
  const loadPrismaClient = (dbType) => {
107
- const paths = [
108
- // Lambda layer location (when using Prisma Lambda layer)
109
- `/opt/nodejs/node_modules/generated/prisma-${dbType}`,
110
- // Local development location (relative to core package)
125
+ const fs = require('fs');
126
+ const layerPath = `/opt/nodejs/node_modules/generated/prisma-${dbType}`;
127
+
128
+ // Check if layer exists (when usePrismaLambdaLayer=true)
129
+ if (fs.existsSync(layerPath)) {
130
+ try {
131
+ return require(layerPath).PrismaClient;
132
+ } catch (err) {
133
+ // Layer exists but failed to load - fall through to bundled paths
134
+ }
135
+ }
136
+
137
+ // Layer doesn't exist or failed - use bundled/local paths (when usePrismaLambdaLayer=false)
138
+ const localPaths = [
139
+ // Bundled with function (when usePrismaLambdaLayer=false)
140
+ `@friggframework/core/generated/prisma-${dbType}`,
141
+ // Local development (relative to core package)
111
142
  `../generated/prisma-${dbType}`,
112
143
  ];
113
144
 
114
- for (const path of paths) {
145
+ for (const path of localPaths) {
115
146
  try {
116
147
  return require(path).PrismaClient;
117
148
  } catch (err) {
@@ -120,7 +151,8 @@ const prismaClientSingleton = () => {
120
151
  }
121
152
 
122
153
  throw new Error(
123
- `Cannot find Prisma client for ${dbType}. Tried paths: ${paths.join(', ')}`
154
+ `Cannot find Prisma client for ${dbType}. ` +
155
+ `Tried layer path: ${layerPath}, local paths: ${localPaths.join(', ')}`
124
156
  );
125
157
  };
126
158
 
@@ -29,32 +29,21 @@ class HealthCheckRepositoryMongoDB extends HealthCheckRepositoryInterface {
29
29
  }
30
30
 
31
31
  return {
32
- readyState: isConnected ? 1 : 0,
33
32
  readyState: isConnected ? 1 : 0,
34
33
  stateName,
35
34
  isConnected,
36
35
  };
37
36
  }
38
37
 
38
+ /**
39
+ * @param {number} maxTimeMS
40
+ * @returns {Promise<number>} Response time in milliseconds
41
+ */
39
42
  async pingDatabase(maxTimeMS = 2000) {
40
43
  const pingStart = Date.now();
41
-
42
- // Create a timeout promise that rejects after maxTimeMS
43
- const timeoutPromise = new Promise((_, reject) =>
44
- setTimeout(() => reject(new Error('Database ping timeout')), maxTimeMS)
45
- );
46
-
47
- // Race between the database ping and the timeout
48
- await Promise.race([
49
- prisma.$queryRaw`SELECT 1`.catch(() => {
50
- // For MongoDB, use runCommandRaw instead
51
- return prisma.$runCommandRaw({ ping: 1 });
52
- }),
53
- timeoutPromise
54
- ]);
55
-
56
- return Date.now() - pingStart;
57
- }
44
+ await this.prisma.$queryRaw`SELECT 1`.catch(() => {
45
+ return this.prisma.$runCommandRaw({ ping: 1 });
46
+ });
58
47
  return Date.now() - pingStart;
59
48
  }
60
49
 
@@ -75,10 +64,17 @@ class HealthCheckRepositoryMongoDB extends HealthCheckRepositoryInterface {
75
64
  * @returns {Promise<Object|null>}
76
65
  */
77
66
  async getRawCredentialById(id) {
78
- const { ObjectId } = require('mongodb');
79
- return await mongoose.connection.db
80
- .collection('Credential')
81
- .findOne({ _id: new ObjectId(id) });
67
+ const result = await this.prisma.$runCommandRaw({
68
+ find: 'Credential',
69
+ filter: { _id: { $oid: id } },
70
+ limit: 1,
71
+ });
72
+
73
+ if (!result.cursor || !result.cursor.firstBatch || result.cursor.firstBatch.length === 0) {
74
+ return null;
75
+ }
76
+
77
+ return result.cursor.firstBatch[0];
82
78
  }
83
79
 
84
80
  async deleteCredential(id) {
@@ -5,11 +5,14 @@
5
5
  * handling the constraint that collections cannot be created inside
6
6
  * multi-document transactions.
7
7
  *
8
+ * Uses Prisma's $runCommandRaw to send native MongoDB commands directly,
9
+ * avoiding the need for mongoose connection.
10
+ *
8
11
  * @see https://github.com/prisma/prisma/issues/8305
9
12
  * @see https://www.mongodb.com/docs/manual/core/transactions/#transactions-and-operations
10
13
  */
11
14
 
12
- const { mongoose } = require('../mongoose');
15
+ const { prisma } = require('../prisma');
13
16
 
14
17
  /**
15
18
  * Ensures a MongoDB collection exists
@@ -18,6 +21,9 @@ const { mongoose } = require('../mongoose');
18
21
  * transactions. This function checks if a collection exists and creates it if needed,
19
22
  * preventing "Cannot create namespace in multi-document transaction" errors.
20
23
  *
24
+ * Uses Prisma's $runCommandRaw to send native MongoDB commands, which works with
25
+ * both MongoDB and DocumentDB.
26
+ *
21
27
  * @param {string} collectionName - Name of the collection to ensure exists
22
28
  * @returns {Promise<void>}
23
29
  *
@@ -30,23 +36,24 @@ const { mongoose } = require('../mongoose');
30
36
  */
31
37
  async function ensureCollectionExists(collectionName) {
32
38
  try {
33
- const collections = await mongoose.connection.db
34
- .listCollections({ name: collectionName })
35
- .toArray();
39
+ // Check if collection exists using Prisma's $runCommandRaw
40
+ const collections = await prisma.$runCommandRaw({
41
+ listCollections: 1,
42
+ filter: { name: collectionName }
43
+ });
36
44
 
37
- if (collections.length === 0) {
38
- // Collection doesn't exist, create it outside of any transaction
39
- await mongoose.connection.db.createCollection(collectionName);
40
- console.log(`Created MongoDB collection: ${collectionName}`);
45
+ if (collections.cursor.firstBatch.length === 0) {
46
+ // Collection doesn't exist, create it
47
+ await prisma.$runCommandRaw({
48
+ create: collectionName
49
+ });
50
+ console.log(`✓ Created collection: ${collectionName}`);
41
51
  }
42
52
  } catch (error) {
43
- // Collection might already exist due to race condition, or other error
44
- // Log warning but don't fail - let subsequent operations handle errors
45
- if (error.codeName === 'NamespaceExists') {
46
- // This is expected in race conditions, silently continue
47
- return;
53
+ // Ignore "already exists" errors (code 48: NamespaceExists)
54
+ if (error.code !== 48 && error.codeName !== 'NamespaceExists') {
55
+ console.warn(`Warning: Could not ensure collection ${collectionName}:`, error.message);
48
56
  }
49
- console.warn(`Error ensuring collection ${collectionName} exists:`, error.message);
50
57
  }
51
58
  }
52
59
 
@@ -73,11 +80,12 @@ async function ensureCollectionsExist(collectionNames) {
73
80
  */
74
81
  async function collectionExists(collectionName) {
75
82
  try {
76
- const collections = await mongoose.connection.db
77
- .listCollections({ name: collectionName })
78
- .toArray();
83
+ const collections = await prisma.$runCommandRaw({
84
+ listCollections: 1,
85
+ filter: { name: collectionName }
86
+ });
79
87
 
80
- return collections.length > 0;
88
+ return collections.cursor.firstBatch.length > 0;
81
89
  } catch (error) {
82
90
  console.error(`Error checking if collection ${collectionName} exists:`, error.message);
83
91
  return false;
@@ -16,7 +16,6 @@
16
16
  * @see https://www.mongodb.com/docs/manual/core/transactions/#transactions-and-operations
17
17
  */
18
18
 
19
- const { mongoose } = require('../mongoose');
20
19
  const { ensureCollectionsExist } = require('./mongodb-collection-utils');
21
20
  const { getCollectionsFromSchemaSync } = require('./prisma-schema-parser');
22
21
  const config = require('../config');
@@ -24,25 +23,29 @@ const config = require('../config');
24
23
  /**
25
24
  * Initialize MongoDB schema by ensuring all collections exist
26
25
  *
27
- * This should be called once at application startup, after the database
28
- * connection is established but before handling any requests.
26
+ * This should be called once at application startup, after Prisma connection
27
+ * is established but before handling any requests.
29
28
  *
30
29
  * Dynamically parses the Prisma schema to extract collection names,
31
30
  * ensuring automatic sync with schema changes.
32
31
  *
32
+ * Uses Prisma's $runCommandRaw to create collections, which works with both
33
+ * MongoDB and DocumentDB without requiring mongoose connection.
34
+ *
33
35
  * Benefits:
34
36
  * - Prevents transaction namespace creation errors
35
37
  * - Fails fast if there are database connection issues
36
38
  * - Ensures consistent state across all instances
37
39
  * - Idempotent - safe to run multiple times
38
40
  * - Automatically syncs with Prisma schema changes
41
+ * - No mongoose dependency required
39
42
  *
40
43
  * @returns {Promise<void>}
41
44
  *
42
45
  * @example
43
46
  * ```js
44
47
  * await connectPrisma();
45
- * await initializeMongoDBSchema(); // Run after connection
48
+ * await initializeMongoDBSchema(); // Run after Prisma connection
46
49
  * // Now safe to handle requests
47
50
  * ```
48
51
  */
@@ -53,14 +56,6 @@ async function initializeMongoDBSchema() {
53
56
  return;
54
57
  }
55
58
 
56
- // Check if database is connected
57
- if (mongoose.connection.readyState !== 1) {
58
- throw new Error(
59
- 'Cannot initialize MongoDB schema - database not connected. ' +
60
- 'Call connectPrisma() before initializeMongoDBSchema()'
61
- );
62
- }
63
-
64
59
  console.log('Initializing MongoDB schema - ensuring all collections exist...');
65
60
  const startTime = Date.now();
66
61
 
@@ -35,12 +35,12 @@ exports.Prisma = Prisma
35
35
  exports.$Enums = {}
36
36
 
37
37
  /**
38
- * Prisma Client JS version: 6.17.0
39
- * Query Engine version: c0aafc03b8ef6cdced8654b9a817999e02457d6a
38
+ * Prisma Client JS version: 6.18.0
39
+ * Query Engine version: 34b5a692b7bd79939a9a2c3ef97d816e749cda2f
40
40
  */
41
41
  Prisma.prismaVersion = {
42
- client: "6.17.0",
43
- engine: "c0aafc03b8ef6cdced8654b9a817999e02457d6a"
42
+ client: "6.18.0",
43
+ engine: "34b5a692b7bd79939a9a2c3ef97d816e749cda2f"
44
44
  }
45
45
 
46
46
  Prisma.PrismaClientKnownRequestError = PrismaClientKnownRequestError;
@@ -291,8 +291,8 @@ const config = {
291
291
  "rootEnvPath": null
292
292
  },
293
293
  "relativePath": "../../prisma-mongodb",
294
- "clientVersion": "6.17.0",
295
- "engineVersion": "c0aafc03b8ef6cdced8654b9a817999e02457d6a",
294
+ "clientVersion": "6.18.0",
295
+ "engineVersion": "34b5a692b7bd79939a9a2c3ef97d816e749cda2f",
296
296
  "datasourceNames": [
297
297
  "db"
298
298
  ],
@@ -20,12 +20,12 @@ exports.Prisma = Prisma
20
20
  exports.$Enums = {}
21
21
 
22
22
  /**
23
- * Prisma Client JS version: 6.17.0
24
- * Query Engine version: c0aafc03b8ef6cdced8654b9a817999e02457d6a
23
+ * Prisma Client JS version: 6.18.0
24
+ * Query Engine version: 34b5a692b7bd79939a9a2c3ef97d816e749cda2f
25
25
  */
26
26
  Prisma.prismaVersion = {
27
- client: "6.17.0",
28
- engine: "c0aafc03b8ef6cdced8654b9a817999e02457d6a"
27
+ client: "6.18.0",
28
+ engine: "34b5a692b7bd79939a9a2c3ef97d816e749cda2f"
29
29
  }
30
30
 
31
31
  Prisma.PrismaClientKnownRequestError = () => {
@@ -403,8 +403,8 @@ export namespace Prisma {
403
403
  export import Exact = $Public.Exact
404
404
 
405
405
  /**
406
- * Prisma Client JS version: 6.17.0
407
- * Query Engine version: c0aafc03b8ef6cdced8654b9a817999e02457d6a
406
+ * Prisma Client JS version: 6.18.0
407
+ * Query Engine version: 34b5a692b7bd79939a9a2c3ef97d816e749cda2f
408
408
  */
409
409
  export type PrismaVersion = {
410
410
  client: string
@@ -417,6 +417,7 @@ export namespace Prisma {
417
417
  */
418
418
 
419
419
 
420
+ export import Bytes = runtime.Bytes
420
421
  export import JsonObject = runtime.JsonObject
421
422
  export import JsonArray = runtime.JsonArray
422
423
  export import JsonValue = runtime.JsonValue
@@ -35,12 +35,12 @@ exports.Prisma = Prisma
35
35
  exports.$Enums = {}
36
36
 
37
37
  /**
38
- * Prisma Client JS version: 6.17.0
39
- * Query Engine version: c0aafc03b8ef6cdced8654b9a817999e02457d6a
38
+ * Prisma Client JS version: 6.18.0
39
+ * Query Engine version: 34b5a692b7bd79939a9a2c3ef97d816e749cda2f
40
40
  */
41
41
  Prisma.prismaVersion = {
42
- client: "6.17.0",
43
- engine: "c0aafc03b8ef6cdced8654b9a817999e02457d6a"
42
+ client: "6.18.0",
43
+ engine: "34b5a692b7bd79939a9a2c3ef97d816e749cda2f"
44
44
  }
45
45
 
46
46
  Prisma.PrismaClientKnownRequestError = PrismaClientKnownRequestError;
@@ -292,8 +292,8 @@ const config = {
292
292
  "rootEnvPath": null
293
293
  },
294
294
  "relativePath": "../../prisma-mongodb",
295
- "clientVersion": "6.17.0",
296
- "engineVersion": "c0aafc03b8ef6cdced8654b9a817999e02457d6a",
295
+ "clientVersion": "6.18.0",
296
+ "engineVersion": "34b5a692b7bd79939a9a2c3ef97d816e749cda2f",
297
297
  "datasourceNames": [
298
298
  "db"
299
299
  ],
@@ -151,7 +151,7 @@
151
151
  },
152
152
  "./*": "./*"
153
153
  },
154
- "version": "6.17.0",
154
+ "version": "6.18.0",
155
155
  "sideEffects": false,
156
156
  "imports": {
157
157
  "#wasm-engine-loader": {