@friggframework/core 2.0.0-next.52 → 2.0.0-next.54
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.
- package/CLAUDE.md +2 -1
- package/application/commands/integration-commands.js +1 -1
- package/application/index.js +1 -1
- package/credential/repositories/credential-repository-documentdb.js +300 -0
- package/credential/repositories/credential-repository-factory.js +8 -1
- package/database/config.js +4 -4
- package/database/documentdb-encryption-service.js +330 -0
- package/database/documentdb-utils.js +136 -0
- package/database/encryption/README.md +50 -0
- package/database/encryption/documentdb-encryption-service.md +3270 -0
- package/database/encryption/encryption-schema-registry.js +46 -0
- package/database/prisma.js +7 -47
- package/database/repositories/health-check-repository-documentdb.js +134 -0
- package/database/repositories/health-check-repository-factory.js +6 -1
- package/database/repositories/health-check-repository-interface.js +29 -34
- package/database/repositories/health-check-repository-mongodb.js +1 -3
- package/database/use-cases/check-database-state-use-case.js +3 -3
- package/database/use-cases/run-database-migration-use-case.js +6 -4
- package/database/use-cases/trigger-database-migration-use-case.js +2 -2
- package/database/utils/mongodb-schema-init.js +5 -5
- package/database/utils/prisma-runner.js +15 -9
- package/generated/prisma-mongodb/edge.js +9 -9
- package/generated/prisma-mongodb/index-browser.js +4 -4
- package/generated/prisma-mongodb/index.d.ts +12 -7
- package/generated/prisma-mongodb/index.js +9 -9
- package/generated/prisma-mongodb/package.json +2 -2
- package/generated/prisma-mongodb/query-engine-debian-openssl-3.0.x +0 -0
- package/generated/prisma-mongodb/query-engine-rhel-openssl-3.0.x +0 -0
- package/generated/prisma-mongodb/runtime/binary.js +2 -2
- package/generated/prisma-mongodb/runtime/edge-esm.js +3 -3
- package/generated/prisma-mongodb/runtime/edge.js +3 -3
- package/generated/prisma-mongodb/runtime/library.d.ts +0 -5
- package/generated/prisma-mongodb/runtime/react-native.js +14 -14
- package/generated/prisma-mongodb/runtime/wasm-compiler-edge.js +18 -18
- package/generated/prisma-mongodb/runtime/wasm-engine-edge.js +11 -11
- package/generated/prisma-mongodb/schema.prisma +1 -3
- package/generated/prisma-mongodb/wasm.js +8 -8
- package/generated/prisma-postgresql/edge.js +9 -9
- package/generated/prisma-postgresql/index-browser.js +4 -4
- package/generated/prisma-postgresql/index.d.ts +12 -7
- package/generated/prisma-postgresql/index.js +9 -9
- package/generated/prisma-postgresql/package.json +2 -2
- package/generated/prisma-postgresql/query-engine-debian-openssl-3.0.x +0 -0
- package/generated/prisma-postgresql/query-engine-rhel-openssl-3.0.x +0 -0
- package/generated/prisma-postgresql/query_engine_bg.js +2 -2
- package/generated/prisma-postgresql/query_engine_bg.wasm +0 -0
- package/generated/prisma-postgresql/runtime/binary.js +2 -2
- package/generated/prisma-postgresql/runtime/edge-esm.js +3 -3
- package/generated/prisma-postgresql/runtime/edge.js +3 -3
- package/generated/prisma-postgresql/runtime/library.d.ts +0 -5
- package/generated/prisma-postgresql/runtime/react-native.js +14 -14
- package/generated/prisma-postgresql/runtime/wasm-compiler-edge.js +18 -18
- package/generated/prisma-postgresql/runtime/wasm-engine-edge.js +11 -11
- package/generated/prisma-postgresql/schema.prisma +1 -3
- package/generated/prisma-postgresql/wasm.js +8 -8
- package/handlers/routers/db-migration.js +2 -3
- package/handlers/routers/health.js +0 -3
- package/handlers/workers/db-migration.js +8 -8
- package/integrations/repositories/integration-mapping-repository-documentdb.js +135 -0
- package/integrations/repositories/integration-mapping-repository-factory.js +8 -1
- package/integrations/repositories/integration-repository-documentdb.js +189 -0
- package/integrations/repositories/integration-repository-factory.js +8 -1
- package/integrations/repositories/process-repository-documentdb.js +141 -0
- package/integrations/repositories/process-repository-factory.js +8 -1
- package/modules/repositories/module-repository-documentdb.js +307 -0
- package/modules/repositories/module-repository-factory.js +8 -1
- package/package.json +5 -5
- package/prisma-mongodb/schema.prisma +1 -3
- package/prisma-postgresql/migrations/20251112195422_update_user_unique_constraints/migration.sql +69 -0
- package/prisma-postgresql/schema.prisma +1 -3
- package/syncs/repositories/sync-repository-documentdb.js +240 -0
- package/syncs/repositories/sync-repository-factory.js +6 -1
- package/token/repositories/token-repository-documentdb.js +125 -0
- package/token/repositories/token-repository-factory.js +8 -1
- package/user/repositories/user-repository-documentdb.js +292 -0
- package/user/repositories/user-repository-factory.js +6 -1
- package/websocket/repositories/websocket-connection-repository-documentdb.js +119 -0
- package/websocket/repositories/websocket-connection-repository-factory.js +8 -1
|
@@ -35,12 +35,12 @@ exports.Prisma = Prisma
|
|
|
35
35
|
exports.$Enums = {}
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
* Prisma Client JS version: 6.
|
|
39
|
-
* Query Engine version:
|
|
38
|
+
* Prisma Client JS version: 6.17.0
|
|
39
|
+
* Query Engine version: c0aafc03b8ef6cdced8654b9a817999e02457d6a
|
|
40
40
|
*/
|
|
41
41
|
Prisma.prismaVersion = {
|
|
42
|
-
client: "6.
|
|
43
|
-
engine: "
|
|
42
|
+
client: "6.17.0",
|
|
43
|
+
engine: "c0aafc03b8ef6cdced8654b9a817999e02457d6a"
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
Prisma.PrismaClientKnownRequestError = PrismaClientKnownRequestError;
|
|
@@ -313,8 +313,8 @@ const config = {
|
|
|
313
313
|
"rootEnvPath": null
|
|
314
314
|
},
|
|
315
315
|
"relativePath": "../../prisma-postgresql",
|
|
316
|
-
"clientVersion": "6.
|
|
317
|
-
"engineVersion": "
|
|
316
|
+
"clientVersion": "6.17.0",
|
|
317
|
+
"engineVersion": "c0aafc03b8ef6cdced8654b9a817999e02457d6a",
|
|
318
318
|
"datasourceNames": [
|
|
319
319
|
"db"
|
|
320
320
|
],
|
|
@@ -329,8 +329,8 @@ const config = {
|
|
|
329
329
|
}
|
|
330
330
|
}
|
|
331
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": "
|
|
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([username, appUserId])\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": "fdfa5441e78673a19ad3ef34a678ad7ac9afa58837e86fbe0c2b6c591d151938",
|
|
334
334
|
"copyEngine": true
|
|
335
335
|
}
|
|
336
336
|
config.dirname = '/'
|
|
@@ -85,7 +85,7 @@ router.use(validateApiKey);
|
|
|
85
85
|
* Request body:
|
|
86
86
|
* {
|
|
87
87
|
* userId: string (optional, defaults to 'admin'),
|
|
88
|
-
* dbType: 'postgresql' | 'mongodb',
|
|
88
|
+
* dbType: 'postgresql' | 'mongodb' | 'documentdb',
|
|
89
89
|
* stage: string (e.g., 'production', 'dev')
|
|
90
90
|
* }
|
|
91
91
|
*
|
|
@@ -101,8 +101,7 @@ router.use(validateApiKey);
|
|
|
101
101
|
router.post(
|
|
102
102
|
'/db-migrate',
|
|
103
103
|
catchAsyncError(async (req, res) => {
|
|
104
|
-
|
|
105
|
-
const dbType = 'postgresql';
|
|
104
|
+
const dbType = req.body.dbType || process.env.DB_TYPE || 'postgresql';
|
|
106
105
|
const { stage } = req.body;
|
|
107
106
|
// TODO: Extract userId from JWT token when auth is implemented
|
|
108
107
|
const userId = req.body.userId || 'admin';
|
|
@@ -8,9 +8,6 @@ const {
|
|
|
8
8
|
const {
|
|
9
9
|
createModuleRepository,
|
|
10
10
|
} = require('../../modules/repositories/module-repository-factory');
|
|
11
|
-
const {
|
|
12
|
-
createIntegrationRepository,
|
|
13
|
-
} = require('../../integrations/repositories/integration-repository-factory');
|
|
14
11
|
const {
|
|
15
12
|
createHealthCheckRepository,
|
|
16
13
|
} = require('../../database/repositories/health-check-repository-factory');
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* ensuring consistency with the `frigg db:setup` command.
|
|
9
9
|
*
|
|
10
10
|
* Environment Variables Required:
|
|
11
|
-
* - DATABASE_URL:
|
|
12
|
-
* - DB_TYPE: Database type ('postgresql' or '
|
|
11
|
+
* - DATABASE_URL: Database connection string (automatically set from Secrets Manager)
|
|
12
|
+
* - DB_TYPE: Database type ('postgresql', 'mongodb', or 'documentdb')
|
|
13
13
|
* - STAGE: Deployment stage (determines migration command: 'dev' or 'deploy')
|
|
14
14
|
*
|
|
15
15
|
* Invocation:
|
|
@@ -103,31 +103,31 @@ function sanitizeDatabaseUrl(url) {
|
|
|
103
103
|
function extractMigrationParams(event) {
|
|
104
104
|
let migrationId = null;
|
|
105
105
|
let stage = null;
|
|
106
|
-
|
|
107
|
-
// Migration infrastructure is PostgreSQL-only, so hardcode dbType
|
|
108
|
-
const dbType = 'postgresql';
|
|
106
|
+
let dbType = process.env.DB_TYPE || 'postgresql';
|
|
109
107
|
|
|
110
108
|
// Check if this is an SQS event
|
|
111
109
|
if (event.Records && event.Records.length > 0) {
|
|
112
110
|
// SQS event - extract from message body
|
|
113
111
|
const message = JSON.parse(event.Records[0].body);
|
|
114
112
|
migrationId = message.migrationId;
|
|
115
|
-
stage = message.stage;
|
|
113
|
+
stage = message.stage || process.env.STAGE || 'production';
|
|
114
|
+
dbType = message.dbType || dbType;
|
|
116
115
|
|
|
117
116
|
console.log('SQS event detected');
|
|
118
117
|
console.log(` Migration ID: ${migrationId}`);
|
|
119
|
-
console.log(` DB Type: ${dbType}
|
|
118
|
+
console.log(` DB Type: ${dbType}`);
|
|
120
119
|
console.log(` Stage: ${stage}`);
|
|
121
120
|
} else {
|
|
122
121
|
// Direct invocation - use event properties or environment variables
|
|
123
122
|
migrationId = event.migrationId || null;
|
|
124
123
|
stage = event.stage || process.env.STAGE || 'production';
|
|
124
|
+
dbType = event.dbType || dbType;
|
|
125
125
|
|
|
126
126
|
console.log('Direct invocation detected');
|
|
127
127
|
if (migrationId) {
|
|
128
128
|
console.log(` Migration ID: ${migrationId}`);
|
|
129
129
|
}
|
|
130
|
-
console.log(` DB Type: ${dbType}
|
|
130
|
+
console.log(` DB Type: ${dbType}`);
|
|
131
131
|
console.log(` Stage: ${stage}`);
|
|
132
132
|
}
|
|
133
133
|
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
const { prisma } = require('../../database/prisma');
|
|
2
|
+
const {
|
|
3
|
+
toObjectId,
|
|
4
|
+
fromObjectId,
|
|
5
|
+
findMany,
|
|
6
|
+
findOne,
|
|
7
|
+
insertOne,
|
|
8
|
+
updateOne,
|
|
9
|
+
deleteOne,
|
|
10
|
+
deleteMany,
|
|
11
|
+
} = require('../../database/documentdb-utils');
|
|
12
|
+
const {
|
|
13
|
+
IntegrationMappingRepositoryInterface,
|
|
14
|
+
} = require('./integration-mapping-repository-interface');
|
|
15
|
+
|
|
16
|
+
class IntegrationMappingRepositoryDocumentDB extends IntegrationMappingRepositoryInterface {
|
|
17
|
+
constructor() {
|
|
18
|
+
super();
|
|
19
|
+
this.prisma = prisma;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async findMappingBy(integrationId, sourceId) {
|
|
23
|
+
const filter = this._compositeFilter(integrationId, sourceId);
|
|
24
|
+
const doc = await findOne(this.prisma, 'IntegrationMapping', filter);
|
|
25
|
+
return doc ? this._mapMapping(doc) : null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async upsertMapping(integrationId, sourceId, mapping) {
|
|
29
|
+
const filter = this._compositeFilter(integrationId, sourceId);
|
|
30
|
+
const existing = await findOne(this.prisma, 'IntegrationMapping', filter);
|
|
31
|
+
const now = new Date();
|
|
32
|
+
|
|
33
|
+
if (existing) {
|
|
34
|
+
await updateOne(
|
|
35
|
+
this.prisma,
|
|
36
|
+
'IntegrationMapping',
|
|
37
|
+
{ _id: existing._id },
|
|
38
|
+
{
|
|
39
|
+
$set: {
|
|
40
|
+
mapping,
|
|
41
|
+
updatedAt: now,
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
const updated = await findOne(this.prisma, 'IntegrationMapping', { _id: existing._id });
|
|
46
|
+
return this._mapMapping(updated);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const document = {
|
|
50
|
+
integrationId: toObjectId(integrationId),
|
|
51
|
+
sourceId: sourceId === null || sourceId === undefined ? null : String(sourceId),
|
|
52
|
+
mapping,
|
|
53
|
+
createdAt: now,
|
|
54
|
+
updatedAt: now,
|
|
55
|
+
};
|
|
56
|
+
const insertedId = await insertOne(this.prisma, 'IntegrationMapping', document);
|
|
57
|
+
const created = await findOne(this.prisma, 'IntegrationMapping', { _id: insertedId });
|
|
58
|
+
return this._mapMapping(created);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async findMappingsByIntegration(integrationId) {
|
|
62
|
+
const filter = {};
|
|
63
|
+
const integrationObjectId = toObjectId(integrationId);
|
|
64
|
+
if (integrationObjectId) filter.integrationId = integrationObjectId;
|
|
65
|
+
const docs = await findMany(this.prisma, 'IntegrationMapping', filter);
|
|
66
|
+
return docs.map((doc) => this._mapMapping(doc));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async deleteMapping(integrationId, sourceId) {
|
|
70
|
+
const filter = this._compositeFilter(integrationId, sourceId);
|
|
71
|
+
const result = await deleteOne(this.prisma, 'IntegrationMapping', filter);
|
|
72
|
+
const deleted = result?.n ?? 0;
|
|
73
|
+
return { acknowledged: true, deletedCount: deleted };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async deleteMappingsByIntegration(integrationId) {
|
|
77
|
+
const integrationObjectId = toObjectId(integrationId);
|
|
78
|
+
if (!integrationObjectId) {
|
|
79
|
+
return { acknowledged: true, deletedCount: 0 };
|
|
80
|
+
}
|
|
81
|
+
const result = await deleteMany(this.prisma, 'IntegrationMapping', {
|
|
82
|
+
integrationId: integrationObjectId,
|
|
83
|
+
});
|
|
84
|
+
const deleted = result?.n ?? 0;
|
|
85
|
+
return { acknowledged: true, deletedCount: deleted };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async findMappingById(id) {
|
|
89
|
+
const objectId = toObjectId(id);
|
|
90
|
+
if (!objectId) return null;
|
|
91
|
+
const doc = await findOne(this.prisma, 'IntegrationMapping', { _id: objectId });
|
|
92
|
+
return doc ? this._mapMapping(doc) : null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async updateMapping(id, updates) {
|
|
96
|
+
const objectId = toObjectId(id);
|
|
97
|
+
if (!objectId) return null;
|
|
98
|
+
await updateOne(
|
|
99
|
+
this.prisma,
|
|
100
|
+
'IntegrationMapping',
|
|
101
|
+
{ _id: objectId },
|
|
102
|
+
{
|
|
103
|
+
$set: {
|
|
104
|
+
...updates,
|
|
105
|
+
updatedAt: new Date(),
|
|
106
|
+
},
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
const updated = await findOne(this.prisma, 'IntegrationMapping', { _id: objectId });
|
|
110
|
+
return updated ? this._mapMapping(updated) : null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
_compositeFilter(integrationId, sourceId) {
|
|
114
|
+
const filter = {};
|
|
115
|
+
const integrationObjectId = toObjectId(integrationId);
|
|
116
|
+
if (integrationObjectId) filter.integrationId = integrationObjectId;
|
|
117
|
+
if (sourceId !== undefined) {
|
|
118
|
+
filter.sourceId = sourceId === null ? null : String(sourceId);
|
|
119
|
+
}
|
|
120
|
+
return filter;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
_mapMapping(doc) {
|
|
124
|
+
return {
|
|
125
|
+
id: fromObjectId(doc?._id),
|
|
126
|
+
integrationId: fromObjectId(doc?.integrationId),
|
|
127
|
+
sourceId: doc?.sourceId ?? null,
|
|
128
|
+
mapping: doc?.mapping ?? null,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
module.exports = { IntegrationMappingRepositoryDocumentDB };
|
|
134
|
+
|
|
135
|
+
|
|
@@ -4,6 +4,9 @@ const {
|
|
|
4
4
|
const {
|
|
5
5
|
IntegrationMappingRepositoryPostgres,
|
|
6
6
|
} = require('./integration-mapping-repository-postgres');
|
|
7
|
+
const {
|
|
8
|
+
IntegrationMappingRepositoryDocumentDB,
|
|
9
|
+
} = require('./integration-mapping-repository-documentdb');
|
|
7
10
|
const config = require('../../database/config');
|
|
8
11
|
|
|
9
12
|
/**
|
|
@@ -35,9 +38,12 @@ function createIntegrationMappingRepository() {
|
|
|
35
38
|
case 'postgresql':
|
|
36
39
|
return new IntegrationMappingRepositoryPostgres();
|
|
37
40
|
|
|
41
|
+
case 'documentdb':
|
|
42
|
+
return new IntegrationMappingRepositoryDocumentDB();
|
|
43
|
+
|
|
38
44
|
default:
|
|
39
45
|
throw new Error(
|
|
40
|
-
`Unsupported database type: ${dbType}. Supported values: 'mongodb', 'postgresql'`
|
|
46
|
+
`Unsupported database type: ${dbType}. Supported values: 'mongodb', 'documentdb', 'postgresql'`
|
|
41
47
|
);
|
|
42
48
|
}
|
|
43
49
|
}
|
|
@@ -47,4 +53,5 @@ module.exports = {
|
|
|
47
53
|
// Export adapters for direct testing
|
|
48
54
|
IntegrationMappingRepositoryMongo,
|
|
49
55
|
IntegrationMappingRepositoryPostgres,
|
|
56
|
+
IntegrationMappingRepositoryDocumentDB,
|
|
50
57
|
};
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
const { prisma } = require('../../database/prisma');
|
|
2
|
+
const {
|
|
3
|
+
toObjectId,
|
|
4
|
+
toObjectIdArray,
|
|
5
|
+
fromObjectId,
|
|
6
|
+
findMany,
|
|
7
|
+
findOne,
|
|
8
|
+
insertOne,
|
|
9
|
+
updateOne,
|
|
10
|
+
deleteOne,
|
|
11
|
+
} = require('../../database/documentdb-utils');
|
|
12
|
+
const {
|
|
13
|
+
IntegrationRepositoryInterface,
|
|
14
|
+
} = require('./integration-repository-interface');
|
|
15
|
+
|
|
16
|
+
class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
|
|
17
|
+
constructor() {
|
|
18
|
+
super();
|
|
19
|
+
this.prisma = prisma;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async findIntegrationsByUserId(userId) {
|
|
23
|
+
const objectId = toObjectId(userId);
|
|
24
|
+
const filter = objectId ? { userId: objectId } : {};
|
|
25
|
+
const records = await findMany(this.prisma, 'Integration', filter);
|
|
26
|
+
return records.map((doc) => this._mapIntegration(doc));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async deleteIntegrationById(integrationId) {
|
|
30
|
+
const objectId = toObjectId(integrationId);
|
|
31
|
+
if (!objectId) return { acknowledged: true, deletedCount: 0 };
|
|
32
|
+
const result = await deleteOne(this.prisma, 'Integration', { _id: objectId });
|
|
33
|
+
const deleted = result?.n ?? 0;
|
|
34
|
+
return { acknowledged: true, deletedCount: deleted };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async findIntegrationByName(name) {
|
|
38
|
+
const doc = await findOne(this.prisma, 'Integration', { 'config.type': name });
|
|
39
|
+
if (!doc) {
|
|
40
|
+
throw new Error(`Integration with name ${name} not found`);
|
|
41
|
+
}
|
|
42
|
+
return this._mapIntegration(doc);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async findIntegrationById(id) {
|
|
46
|
+
const objectId = toObjectId(id);
|
|
47
|
+
if (!objectId) {
|
|
48
|
+
throw new Error(`Integration with id ${id} not found`);
|
|
49
|
+
}
|
|
50
|
+
const doc = await findOne(this.prisma, 'Integration', { _id: objectId });
|
|
51
|
+
if (!doc) {
|
|
52
|
+
throw new Error(`Integration with id ${id} not found`);
|
|
53
|
+
}
|
|
54
|
+
return this._mapIntegration(doc);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async updateIntegrationStatus(integrationId, status) {
|
|
58
|
+
const objectId = toObjectId(integrationId);
|
|
59
|
+
if (!objectId) return false;
|
|
60
|
+
await updateOne(
|
|
61
|
+
this.prisma,
|
|
62
|
+
'Integration',
|
|
63
|
+
{ _id: objectId },
|
|
64
|
+
{
|
|
65
|
+
$set: { status, updatedAt: new Date() },
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async updateIntegrationMessages(
|
|
72
|
+
integrationId,
|
|
73
|
+
messageType,
|
|
74
|
+
messageTitle,
|
|
75
|
+
messageBody,
|
|
76
|
+
messageTimestamp
|
|
77
|
+
) {
|
|
78
|
+
const objectId = toObjectId(integrationId);
|
|
79
|
+
if (!objectId) {
|
|
80
|
+
throw new Error(`Integration ${integrationId} not found`);
|
|
81
|
+
}
|
|
82
|
+
const existing = await findOne(this.prisma, 'Integration', { _id: objectId });
|
|
83
|
+
if (!existing) {
|
|
84
|
+
throw new Error(`Integration ${integrationId} not found`);
|
|
85
|
+
}
|
|
86
|
+
const messages = this._extractMessages(existing);
|
|
87
|
+
const list = Array.isArray(messages[messageType]) ? [...messages[messageType]] : [];
|
|
88
|
+
list.push({
|
|
89
|
+
title: messageTitle ?? null,
|
|
90
|
+
message: messageBody,
|
|
91
|
+
timestamp: messageTimestamp,
|
|
92
|
+
});
|
|
93
|
+
const updatedMessages = { ...messages, [messageType]: list };
|
|
94
|
+
await updateOne(
|
|
95
|
+
this.prisma,
|
|
96
|
+
'Integration',
|
|
97
|
+
{ _id: objectId },
|
|
98
|
+
{
|
|
99
|
+
$set: {
|
|
100
|
+
messages: updatedMessages,
|
|
101
|
+
errors: updatedMessages.errors ?? [],
|
|
102
|
+
warnings: updatedMessages.warnings ?? [],
|
|
103
|
+
info: updatedMessages.info ?? [],
|
|
104
|
+
logs: updatedMessages.logs ?? [],
|
|
105
|
+
updatedAt: new Date(),
|
|
106
|
+
},
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async createIntegration(entities, userId, config) {
|
|
113
|
+
const now = new Date();
|
|
114
|
+
const document = {
|
|
115
|
+
userId: toObjectId(userId) || null,
|
|
116
|
+
config,
|
|
117
|
+
version: '0.0.0',
|
|
118
|
+
status: 'ENABLED',
|
|
119
|
+
entityIds: toObjectIdArray(entities),
|
|
120
|
+
messages: { errors: [], warnings: [], info: [], logs: [] },
|
|
121
|
+
errors: [],
|
|
122
|
+
warnings: [],
|
|
123
|
+
info: [],
|
|
124
|
+
logs: [],
|
|
125
|
+
createdAt: now,
|
|
126
|
+
updatedAt: now,
|
|
127
|
+
};
|
|
128
|
+
const insertedId = await insertOne(this.prisma, 'Integration', document);
|
|
129
|
+
const created = await findOne(this.prisma, 'Integration', { _id: insertedId });
|
|
130
|
+
return this._mapIntegration(created);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async findIntegrationByUserId(userId) {
|
|
134
|
+
const objectId = toObjectId(userId);
|
|
135
|
+
if (!objectId) return null;
|
|
136
|
+
const doc = await findOne(this.prisma, 'Integration', { userId: objectId });
|
|
137
|
+
return doc ? this._mapIntegration(doc) : null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async updateIntegrationConfig(integrationId, config) {
|
|
141
|
+
if (config === null || config === undefined) {
|
|
142
|
+
throw new Error('Config parameter is required');
|
|
143
|
+
}
|
|
144
|
+
const objectId = toObjectId(integrationId);
|
|
145
|
+
if (!objectId) {
|
|
146
|
+
throw new Error(`Integration with id ${integrationId} not found`);
|
|
147
|
+
}
|
|
148
|
+
await updateOne(
|
|
149
|
+
this.prisma,
|
|
150
|
+
'Integration',
|
|
151
|
+
{ _id: objectId },
|
|
152
|
+
{
|
|
153
|
+
$set: {
|
|
154
|
+
config,
|
|
155
|
+
updatedAt: new Date(),
|
|
156
|
+
},
|
|
157
|
+
}
|
|
158
|
+
);
|
|
159
|
+
const updated = await findOne(this.prisma, 'Integration', { _id: objectId });
|
|
160
|
+
return this._mapIntegration(updated);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
_mapIntegration(doc) {
|
|
164
|
+
const messages = this._extractMessages(doc);
|
|
165
|
+
return {
|
|
166
|
+
id: fromObjectId(doc?._id),
|
|
167
|
+
entitiesIds: (doc?.entityIds || []).map((value) => fromObjectId(value)),
|
|
168
|
+
userId: fromObjectId(doc?.userId),
|
|
169
|
+
config: doc?.config ?? null,
|
|
170
|
+
version: doc?.version ?? null,
|
|
171
|
+
status: doc?.status ?? null,
|
|
172
|
+
messages,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
_extractMessages(doc) {
|
|
177
|
+
const base = doc?.messages && typeof doc.messages === 'object' ? doc.messages : {};
|
|
178
|
+
return {
|
|
179
|
+
errors: base.errors ?? doc?.errors ?? [],
|
|
180
|
+
warnings: base.warnings ?? doc?.warnings ?? [],
|
|
181
|
+
info: base.info ?? doc?.info ?? [],
|
|
182
|
+
logs: base.logs ?? doc?.logs ?? [],
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
module.exports = { IntegrationRepositoryDocumentDB };
|
|
188
|
+
|
|
189
|
+
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
const { IntegrationRepositoryMongo } = require('./integration-repository-mongo');
|
|
2
2
|
const { IntegrationRepositoryPostgres } = require('./integration-repository-postgres');
|
|
3
|
+
const {
|
|
4
|
+
IntegrationRepositoryDocumentDB,
|
|
5
|
+
} = require('./integration-repository-documentdb');
|
|
3
6
|
const config = require('../../database/config');
|
|
4
7
|
|
|
5
8
|
/**
|
|
@@ -29,9 +32,12 @@ function createIntegrationRepository() {
|
|
|
29
32
|
case 'postgresql':
|
|
30
33
|
return new IntegrationRepositoryPostgres();
|
|
31
34
|
|
|
35
|
+
case 'documentdb':
|
|
36
|
+
return new IntegrationRepositoryDocumentDB();
|
|
37
|
+
|
|
32
38
|
default:
|
|
33
39
|
throw new Error(
|
|
34
|
-
`Unsupported database type: ${dbType}. Supported values: 'mongodb', 'postgresql'`
|
|
40
|
+
`Unsupported database type: ${dbType}. Supported values: 'mongodb', 'documentdb', 'postgresql'`
|
|
35
41
|
);
|
|
36
42
|
}
|
|
37
43
|
}
|
|
@@ -41,4 +47,5 @@ module.exports = {
|
|
|
41
47
|
// Export adapters for direct testing
|
|
42
48
|
IntegrationRepositoryMongo,
|
|
43
49
|
IntegrationRepositoryPostgres,
|
|
50
|
+
IntegrationRepositoryDocumentDB,
|
|
44
51
|
};
|