@friggframework/core 2.0.0-next.6 → 2.0.0-next.61
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 +694 -0
- package/README.md +959 -50
- package/application/commands/README.md +451 -0
- package/application/commands/credential-commands.js +245 -0
- package/application/commands/entity-commands.js +336 -0
- package/application/commands/integration-commands.js +210 -0
- package/application/commands/user-commands.js +283 -0
- package/application/index.js +69 -0
- package/core/CLAUDE.md +690 -0
- package/core/Worker.js +8 -21
- package/core/create-handler.js +14 -7
- package/credential/repositories/credential-repository-documentdb.js +304 -0
- package/credential/repositories/credential-repository-factory.js +54 -0
- package/credential/repositories/credential-repository-interface.js +98 -0
- package/credential/repositories/credential-repository-mongo.js +269 -0
- package/credential/repositories/credential-repository-postgres.js +291 -0
- package/credential/repositories/credential-repository.js +302 -0
- package/credential/use-cases/get-credential-for-user.js +25 -0
- package/credential/use-cases/update-authentication-status.js +15 -0
- package/database/MONGODB_TRANSACTION_FIX.md +198 -0
- package/database/adapters/lambda-invoker.js +97 -0
- package/database/config.js +154 -0
- package/database/documentdb-encryption-service.js +330 -0
- package/database/documentdb-utils.js +136 -0
- package/database/encryption/README.md +839 -0
- package/database/encryption/documentdb-encryption-service.md +3575 -0
- package/database/encryption/encryption-schema-registry.js +268 -0
- package/database/encryption/field-encryption-service.js +226 -0
- package/database/encryption/logger.js +79 -0
- package/database/encryption/prisma-encryption-extension.js +222 -0
- package/database/index.js +61 -21
- package/database/models/WebsocketConnection.js +16 -10
- package/database/models/readme.md +1 -0
- package/database/prisma.js +182 -0
- package/database/repositories/health-check-repository-documentdb.js +134 -0
- package/database/repositories/health-check-repository-factory.js +48 -0
- package/database/repositories/health-check-repository-interface.js +82 -0
- package/database/repositories/health-check-repository-mongodb.js +89 -0
- package/database/repositories/health-check-repository-postgres.js +82 -0
- package/database/repositories/health-check-repository.js +108 -0
- package/database/repositories/migration-status-repository-s3.js +137 -0
- package/database/use-cases/check-database-health-use-case.js +29 -0
- package/database/use-cases/check-database-state-use-case.js +81 -0
- package/database/use-cases/check-encryption-health-use-case.js +83 -0
- package/database/use-cases/get-database-state-via-worker-use-case.js +61 -0
- package/database/use-cases/get-migration-status-use-case.js +93 -0
- package/database/use-cases/run-database-migration-use-case.js +139 -0
- package/database/use-cases/test-encryption-use-case.js +253 -0
- package/database/use-cases/trigger-database-migration-use-case.js +157 -0
- package/database/utils/mongodb-collection-utils.js +91 -0
- package/database/utils/mongodb-schema-init.js +106 -0
- package/database/utils/prisma-runner.js +477 -0
- package/database/utils/prisma-schema-parser.js +182 -0
- package/docs/PROCESS_MANAGEMENT_QUEUE_SPEC.md +517 -0
- package/encrypt/Cryptor.js +34 -168
- package/encrypt/index.js +1 -2
- package/encrypt/test-encrypt.js +0 -2
- package/errors/client-safe-error.js +26 -0
- package/errors/fetch-error.js +2 -1
- package/errors/index.js +2 -0
- package/generated/prisma-mongodb/client.d.ts +1 -0
- package/generated/prisma-mongodb/client.js +4 -0
- package/generated/prisma-mongodb/default.d.ts +1 -0
- package/generated/prisma-mongodb/default.js +4 -0
- package/generated/prisma-mongodb/edge.d.ts +1 -0
- package/generated/prisma-mongodb/edge.js +334 -0
- package/generated/prisma-mongodb/index-browser.js +316 -0
- package/generated/prisma-mongodb/index.d.ts +22903 -0
- package/generated/prisma-mongodb/index.js +359 -0
- package/generated/prisma-mongodb/package.json +183 -0
- 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.d.ts +1 -0
- package/generated/prisma-mongodb/runtime/binary.js +289 -0
- package/generated/prisma-mongodb/runtime/edge-esm.js +34 -0
- package/generated/prisma-mongodb/runtime/edge.js +34 -0
- package/generated/prisma-mongodb/runtime/index-browser.d.ts +370 -0
- package/generated/prisma-mongodb/runtime/index-browser.js +16 -0
- package/generated/prisma-mongodb/runtime/library.d.ts +3977 -0
- package/generated/prisma-mongodb/runtime/react-native.js +83 -0
- package/generated/prisma-mongodb/runtime/wasm-compiler-edge.js +84 -0
- package/generated/prisma-mongodb/runtime/wasm-engine-edge.js +36 -0
- package/generated/prisma-mongodb/schema.prisma +360 -0
- package/generated/prisma-mongodb/wasm-edge-light-loader.mjs +4 -0
- package/generated/prisma-mongodb/wasm-worker-loader.mjs +4 -0
- package/generated/prisma-mongodb/wasm.d.ts +1 -0
- package/generated/prisma-mongodb/wasm.js +341 -0
- package/generated/prisma-postgresql/client.d.ts +1 -0
- package/generated/prisma-postgresql/client.js +4 -0
- package/generated/prisma-postgresql/default.d.ts +1 -0
- package/generated/prisma-postgresql/default.js +4 -0
- package/generated/prisma-postgresql/edge.d.ts +1 -0
- package/generated/prisma-postgresql/edge.js +356 -0
- package/generated/prisma-postgresql/index-browser.js +338 -0
- package/generated/prisma-postgresql/index.d.ts +25077 -0
- package/generated/prisma-postgresql/index.js +381 -0
- package/generated/prisma-postgresql/package.json +183 -0
- 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 -0
- package/generated/prisma-postgresql/query_engine_bg.wasm +0 -0
- package/generated/prisma-postgresql/runtime/binary.d.ts +1 -0
- package/generated/prisma-postgresql/runtime/binary.js +289 -0
- package/generated/prisma-postgresql/runtime/edge-esm.js +34 -0
- package/generated/prisma-postgresql/runtime/edge.js +34 -0
- package/generated/prisma-postgresql/runtime/index-browser.d.ts +370 -0
- package/generated/prisma-postgresql/runtime/index-browser.js +16 -0
- package/generated/prisma-postgresql/runtime/library.d.ts +3977 -0
- package/generated/prisma-postgresql/runtime/react-native.js +83 -0
- package/generated/prisma-postgresql/runtime/wasm-compiler-edge.js +84 -0
- package/generated/prisma-postgresql/runtime/wasm-engine-edge.js +36 -0
- package/generated/prisma-postgresql/schema.prisma +343 -0
- package/generated/prisma-postgresql/wasm-edge-light-loader.mjs +4 -0
- package/generated/prisma-postgresql/wasm-worker-loader.mjs +4 -0
- package/generated/prisma-postgresql/wasm.d.ts +1 -0
- package/generated/prisma-postgresql/wasm.js +363 -0
- package/handlers/WEBHOOKS.md +653 -0
- package/handlers/app-definition-loader.js +38 -0
- package/handlers/app-handler-helpers.js +56 -0
- package/handlers/backend-utils.js +186 -0
- package/handlers/database-migration-handler.js +227 -0
- package/handlers/integration-event-dispatcher.js +54 -0
- package/handlers/routers/HEALTHCHECK.md +342 -0
- package/handlers/routers/auth.js +15 -0
- package/handlers/routers/db-migration.handler.js +29 -0
- package/handlers/routers/db-migration.js +326 -0
- package/handlers/routers/health.js +516 -0
- package/handlers/routers/integration-defined-routers.js +45 -0
- package/handlers/routers/integration-webhook-routers.js +67 -0
- package/handlers/routers/user.js +63 -0
- package/handlers/routers/websocket.js +57 -0
- package/handlers/use-cases/check-external-apis-health-use-case.js +81 -0
- package/handlers/use-cases/check-integrations-health-use-case.js +44 -0
- package/handlers/workers/db-migration.js +352 -0
- package/handlers/workers/integration-defined-workers.js +27 -0
- package/index.js +77 -22
- package/integrations/WEBHOOK-QUICKSTART.md +151 -0
- package/integrations/index.js +12 -10
- package/integrations/integration-base.js +326 -55
- package/integrations/integration-router.js +374 -179
- package/integrations/options.js +1 -1
- package/integrations/repositories/integration-mapping-repository-documentdb.js +280 -0
- package/integrations/repositories/integration-mapping-repository-factory.js +57 -0
- package/integrations/repositories/integration-mapping-repository-interface.js +106 -0
- package/integrations/repositories/integration-mapping-repository-mongo.js +161 -0
- package/integrations/repositories/integration-mapping-repository-postgres.js +227 -0
- package/integrations/repositories/integration-mapping-repository.js +156 -0
- package/integrations/repositories/integration-repository-documentdb.js +210 -0
- package/integrations/repositories/integration-repository-factory.js +51 -0
- package/integrations/repositories/integration-repository-interface.js +127 -0
- package/integrations/repositories/integration-repository-mongo.js +303 -0
- package/integrations/repositories/integration-repository-postgres.js +352 -0
- package/integrations/repositories/process-repository-documentdb.js +243 -0
- package/integrations/repositories/process-repository-factory.js +53 -0
- package/integrations/repositories/process-repository-interface.js +90 -0
- package/integrations/repositories/process-repository-mongo.js +190 -0
- package/integrations/repositories/process-repository-postgres.js +217 -0
- package/integrations/tests/doubles/config-capturing-integration.js +81 -0
- package/integrations/tests/doubles/dummy-integration-class.js +105 -0
- package/integrations/tests/doubles/test-integration-repository.js +99 -0
- package/integrations/use-cases/create-integration.js +83 -0
- package/integrations/use-cases/create-process.js +128 -0
- package/integrations/use-cases/delete-integration-for-user.js +101 -0
- package/integrations/use-cases/find-integration-context-by-external-entity-id.js +72 -0
- package/integrations/use-cases/get-integration-for-user.js +78 -0
- package/integrations/use-cases/get-integration-instance-by-definition.js +67 -0
- package/integrations/use-cases/get-integration-instance.js +83 -0
- package/integrations/use-cases/get-integrations-for-user.js +88 -0
- package/integrations/use-cases/get-possible-integrations.js +27 -0
- package/integrations/use-cases/get-process.js +87 -0
- package/integrations/use-cases/index.js +19 -0
- package/integrations/use-cases/load-integration-context.js +71 -0
- package/integrations/use-cases/update-integration-messages.js +44 -0
- package/integrations/use-cases/update-integration-status.js +32 -0
- package/integrations/use-cases/update-integration.js +92 -0
- package/integrations/use-cases/update-process-metrics.js +201 -0
- package/integrations/use-cases/update-process-state.js +119 -0
- package/integrations/utils/map-integration-dto.js +37 -0
- package/jest-global-setup-noop.js +3 -0
- package/jest-global-teardown-noop.js +3 -0
- package/logs/logger.js +0 -4
- package/{module-plugin → modules}/entity.js +1 -1
- package/{module-plugin → modules}/index.js +0 -8
- package/modules/module-factory.js +56 -0
- package/modules/module.js +221 -0
- package/modules/repositories/module-repository-documentdb.js +307 -0
- package/modules/repositories/module-repository-factory.js +40 -0
- package/modules/repositories/module-repository-interface.js +129 -0
- package/modules/repositories/module-repository-mongo.js +377 -0
- package/modules/repositories/module-repository-postgres.js +426 -0
- package/modules/repositories/module-repository.js +316 -0
- package/modules/requester/api-key.js +52 -0
- package/{module-plugin → modules}/requester/requester.js +1 -0
- package/{module-plugin → modules}/test/mock-api/api.js +8 -3
- package/{module-plugin → modules}/test/mock-api/definition.js +12 -8
- package/modules/tests/doubles/test-module-factory.js +16 -0
- package/modules/tests/doubles/test-module-repository.js +39 -0
- package/modules/use-cases/get-entities-for-user.js +32 -0
- package/modules/use-cases/get-entity-options-by-id.js +71 -0
- package/modules/use-cases/get-entity-options-by-type.js +34 -0
- package/modules/use-cases/get-module-instance-from-type.js +31 -0
- package/modules/use-cases/get-module.js +74 -0
- package/modules/use-cases/process-authorization-callback.js +133 -0
- package/modules/use-cases/refresh-entity-options.js +72 -0
- package/modules/use-cases/test-module-auth.js +72 -0
- package/modules/utils/map-module-dto.js +18 -0
- package/package.json +82 -50
- package/prisma-mongodb/schema.prisma +360 -0
- package/prisma-postgresql/migrations/20250930193005_init/migration.sql +315 -0
- package/prisma-postgresql/migrations/20251006135218_init/migration.sql +9 -0
- package/prisma-postgresql/migrations/20251010000000_remove_unused_entity_reference_map/migration.sql +3 -0
- package/prisma-postgresql/migrations/20251112195422_update_user_unique_constraints/migration.sql +25 -0
- package/prisma-postgresql/migrations/migration_lock.toml +3 -0
- package/prisma-postgresql/schema.prisma +343 -0
- package/queues/queuer-util.js +27 -22
- package/syncs/manager.js +468 -443
- package/syncs/repositories/sync-repository-documentdb.js +240 -0
- package/syncs/repositories/sync-repository-factory.js +43 -0
- package/syncs/repositories/sync-repository-interface.js +109 -0
- package/syncs/repositories/sync-repository-mongo.js +239 -0
- package/syncs/repositories/sync-repository-postgres.js +319 -0
- package/syncs/sync.js +0 -1
- package/token/repositories/token-repository-documentdb.js +137 -0
- package/token/repositories/token-repository-factory.js +40 -0
- package/token/repositories/token-repository-interface.js +131 -0
- package/token/repositories/token-repository-mongo.js +219 -0
- package/token/repositories/token-repository-postgres.js +264 -0
- package/token/repositories/token-repository.js +219 -0
- package/types/core/index.d.ts +2 -2
- package/types/integrations/index.d.ts +2 -6
- package/types/module-plugin/index.d.ts +5 -59
- package/types/syncs/index.d.ts +0 -2
- package/user/repositories/user-repository-documentdb.js +441 -0
- package/user/repositories/user-repository-factory.js +52 -0
- package/user/repositories/user-repository-interface.js +201 -0
- package/user/repositories/user-repository-mongo.js +308 -0
- package/user/repositories/user-repository-postgres.js +360 -0
- package/user/tests/doubles/test-user-repository.js +72 -0
- package/user/use-cases/authenticate-user.js +127 -0
- package/user/use-cases/authenticate-with-shared-secret.js +48 -0
- package/user/use-cases/create-individual-user.js +61 -0
- package/user/use-cases/create-organization-user.js +47 -0
- package/user/use-cases/create-token-for-user-id.js +30 -0
- package/user/use-cases/get-user-from-adopter-jwt.js +149 -0
- package/user/use-cases/get-user-from-bearer-token.js +77 -0
- package/user/use-cases/get-user-from-x-frigg-headers.js +132 -0
- package/user/use-cases/login-user.js +122 -0
- package/user/user.js +125 -0
- package/utils/backend-path.js +38 -0
- package/utils/index.js +6 -0
- package/websocket/repositories/websocket-connection-repository-documentdb.js +119 -0
- package/websocket/repositories/websocket-connection-repository-factory.js +44 -0
- package/websocket/repositories/websocket-connection-repository-interface.js +106 -0
- package/websocket/repositories/websocket-connection-repository-mongo.js +156 -0
- package/websocket/repositories/websocket-connection-repository-postgres.js +196 -0
- package/websocket/repositories/websocket-connection-repository.js +161 -0
- package/database/models/State.js +0 -9
- package/database/models/Token.js +0 -70
- package/database/mongo.js +0 -45
- package/encrypt/Cryptor.test.js +0 -32
- package/encrypt/encrypt.js +0 -132
- package/encrypt/encrypt.test.js +0 -1069
- package/errors/base-error.test.js +0 -32
- package/errors/fetch-error.test.js +0 -79
- package/errors/halt-error.test.js +0 -11
- package/errors/validation-errors.test.js +0 -120
- package/integrations/create-frigg-backend.js +0 -31
- package/integrations/integration-factory.js +0 -251
- package/integrations/integration-mapping.js +0 -43
- package/integrations/integration-model.js +0 -46
- package/integrations/integration-user.js +0 -144
- package/integrations/test/integration-base.test.js +0 -144
- package/lambda/TimeoutCatcher.test.js +0 -68
- package/logs/logger.test.js +0 -76
- package/module-plugin/auther.js +0 -393
- package/module-plugin/credential.js +0 -22
- package/module-plugin/entity-manager.js +0 -70
- package/module-plugin/manager.js +0 -169
- package/module-plugin/module-factory.js +0 -61
- package/module-plugin/requester/api-key.js +0 -36
- package/module-plugin/requester/requester.test.js +0 -28
- package/module-plugin/test/auther.test.js +0 -97
- /package/{module-plugin → modules}/ModuleConstants.js +0 -0
- /package/{module-plugin → modules}/requester/basic.js +0 -0
- /package/{module-plugin → modules}/requester/oauth-2.js +0 -0
- /package/{module-plugin → modules}/test/mock-api/mocks/hubspot.js +0 -0
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
const {
|
|
2
|
+
createModuleRepository,
|
|
3
|
+
} = require('../../modules/repositories/module-repository-factory');
|
|
4
|
+
|
|
5
|
+
const ERROR_CODE_MAP = {
|
|
6
|
+
ENTITY_NOT_FOUND: 404,
|
|
7
|
+
INVALID_ENTITY_DATA: 400,
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
function mapErrorToResponse(error) {
|
|
11
|
+
const status = ERROR_CODE_MAP[error?.code] || 500;
|
|
12
|
+
return {
|
|
13
|
+
error: status,
|
|
14
|
+
reason: error?.message,
|
|
15
|
+
code: error?.code,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Create entity command factory
|
|
21
|
+
*
|
|
22
|
+
* NOTE: This is an internal API. Integration developers should use createFriggCommands() instead.
|
|
23
|
+
*
|
|
24
|
+
* @returns {Object} Entity command object with CRUD operations
|
|
25
|
+
*/
|
|
26
|
+
function createEntityCommands() {
|
|
27
|
+
const moduleRepo = createModuleRepository();
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
/**
|
|
31
|
+
* Create a new entity
|
|
32
|
+
* @param {Object} params
|
|
33
|
+
* @param {string} params.userId - User ID who owns this entity
|
|
34
|
+
* @param {string} params.externalId - External identifier from the API module
|
|
35
|
+
* @param {string} params.name - Entity name
|
|
36
|
+
* @param {string} params.moduleName - Module name (e.g., 'husbpot', 'frontify')
|
|
37
|
+
* @param {string} [params.credentialId] - Associated credential ID
|
|
38
|
+
* @returns {Promise<Object>} Created entity object
|
|
39
|
+
*/
|
|
40
|
+
async createEntity({
|
|
41
|
+
userId,
|
|
42
|
+
externalId,
|
|
43
|
+
name,
|
|
44
|
+
moduleName,
|
|
45
|
+
credentialId,
|
|
46
|
+
} = {}) {
|
|
47
|
+
try {
|
|
48
|
+
if (!userId || !externalId || !moduleName) {
|
|
49
|
+
const error = new Error(
|
|
50
|
+
'userId, externalId, and moduleName are required'
|
|
51
|
+
);
|
|
52
|
+
error.code = 'INVALID_ENTITY_DATA';
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const entityData = {
|
|
57
|
+
user: userId,
|
|
58
|
+
externalId,
|
|
59
|
+
name,
|
|
60
|
+
moduleName,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
if (credentialId) {
|
|
64
|
+
entityData.credential = credentialId;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const entity = await moduleRepo.createEntity(entityData);
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
id: entity.id,
|
|
71
|
+
userId: entity.userId,
|
|
72
|
+
externalId: entity.externalId,
|
|
73
|
+
name: entity.name,
|
|
74
|
+
moduleName: entity.moduleName,
|
|
75
|
+
credentialId: entity.credential?._id
|
|
76
|
+
? entity.credential._id.toString()
|
|
77
|
+
: entity.credential,
|
|
78
|
+
};
|
|
79
|
+
} catch (error) {
|
|
80
|
+
return mapErrorToResponse(error);
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Find an entity by filter criteria
|
|
86
|
+
* @param {Object} filter
|
|
87
|
+
* @param {string} [filter.externalId] - External ID to search for
|
|
88
|
+
* @param {string} [filter.userId] - User ID to search for
|
|
89
|
+
* @param {string} [filter.moduleName] - Module name to search for
|
|
90
|
+
* @returns {Promise<Object|null>} Entity object or null if not found
|
|
91
|
+
*/
|
|
92
|
+
async findEntity(filter = {}) {
|
|
93
|
+
try {
|
|
94
|
+
if (
|
|
95
|
+
!filter.externalId &&
|
|
96
|
+
!filter.userId &&
|
|
97
|
+
!filter.moduleName
|
|
98
|
+
) {
|
|
99
|
+
const error = new Error(
|
|
100
|
+
'At least one filter criterion is required'
|
|
101
|
+
);
|
|
102
|
+
error.code = 'INVALID_ENTITY_DATA';
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const entity = await moduleRepo.findEntity(filter);
|
|
107
|
+
|
|
108
|
+
if (!entity) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
id: entity.id,
|
|
114
|
+
userId: entity.userId,
|
|
115
|
+
externalId: entity.externalId,
|
|
116
|
+
name: entity.name,
|
|
117
|
+
moduleName: entity.moduleName,
|
|
118
|
+
credentialId: entity.credential?._id
|
|
119
|
+
? entity.credential._id.toString()
|
|
120
|
+
: entity.credential,
|
|
121
|
+
};
|
|
122
|
+
} catch (error) {
|
|
123
|
+
return mapErrorToResponse(error);
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Find all entities for a user
|
|
129
|
+
* @param {string} userId - User ID to search for
|
|
130
|
+
* @returns {Promise<Array>} Array of entity objects
|
|
131
|
+
*/
|
|
132
|
+
async findEntitiesByUserId(userId) {
|
|
133
|
+
try {
|
|
134
|
+
if (!userId) {
|
|
135
|
+
const error = new Error('userId is required');
|
|
136
|
+
error.code = 'INVALID_ENTITY_DATA';
|
|
137
|
+
throw error;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const entities = await moduleRepo.findEntitiesByUserId(userId);
|
|
141
|
+
|
|
142
|
+
return entities.map((entity) => ({
|
|
143
|
+
id: entity.id,
|
|
144
|
+
userId: entity.userId,
|
|
145
|
+
externalId: entity.externalId,
|
|
146
|
+
name: entity.name,
|
|
147
|
+
moduleName: entity.moduleName,
|
|
148
|
+
credentialId: entity.credential?._id
|
|
149
|
+
? entity.credential._id.toString()
|
|
150
|
+
: entity.credential,
|
|
151
|
+
}));
|
|
152
|
+
} catch (error) {
|
|
153
|
+
if (error.code) {
|
|
154
|
+
return mapErrorToResponse(error);
|
|
155
|
+
}
|
|
156
|
+
// For find operations, return empty array on error instead of error object
|
|
157
|
+
return [];
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Find entities by user ID and module name
|
|
163
|
+
* @param {string} userId - User ID to search for
|
|
164
|
+
* @param {string} moduleName - Module name to filter by
|
|
165
|
+
* @returns {Promise<Array>} Array of entity objects
|
|
166
|
+
*/
|
|
167
|
+
async findEntitiesByUserIdAndModuleName(userId, moduleName) {
|
|
168
|
+
try {
|
|
169
|
+
if (!userId || !moduleName) {
|
|
170
|
+
const error = new Error(
|
|
171
|
+
'userId and moduleName are required'
|
|
172
|
+
);
|
|
173
|
+
error.code = 'INVALID_ENTITY_DATA';
|
|
174
|
+
throw error;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const entities =
|
|
178
|
+
await moduleRepo.findEntitiesByUserIdAndModuleName(
|
|
179
|
+
userId,
|
|
180
|
+
moduleName
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
return entities.map((entity) => ({
|
|
184
|
+
id: entity.id,
|
|
185
|
+
userId: entity.userId,
|
|
186
|
+
externalId: entity.externalId,
|
|
187
|
+
name: entity.name,
|
|
188
|
+
moduleName: entity.moduleName,
|
|
189
|
+
credentialId: entity.credential?._id
|
|
190
|
+
? entity.credential._id.toString()
|
|
191
|
+
: entity.credential,
|
|
192
|
+
}));
|
|
193
|
+
} catch (error) {
|
|
194
|
+
if (error.code) {
|
|
195
|
+
return mapErrorToResponse(error);
|
|
196
|
+
}
|
|
197
|
+
return [];
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Find an entity by ID
|
|
203
|
+
* @param {string} entityId - Entity ID to search for
|
|
204
|
+
* @returns {Promise<Object>} Entity object
|
|
205
|
+
*/
|
|
206
|
+
async findEntityById(entityId) {
|
|
207
|
+
try {
|
|
208
|
+
if (!entityId) {
|
|
209
|
+
const error = new Error('entityId is required');
|
|
210
|
+
error.code = 'INVALID_ENTITY_DATA';
|
|
211
|
+
throw error;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const entity = await moduleRepo.findEntityById(entityId);
|
|
215
|
+
|
|
216
|
+
return {
|
|
217
|
+
id: entity.id,
|
|
218
|
+
userId: entity.userId,
|
|
219
|
+
externalId: entity.externalId,
|
|
220
|
+
name: entity.name,
|
|
221
|
+
moduleName: entity.moduleName,
|
|
222
|
+
credentialId: entity.credential?._id
|
|
223
|
+
? entity.credential._id.toString()
|
|
224
|
+
: entity.credential,
|
|
225
|
+
};
|
|
226
|
+
} catch (error) {
|
|
227
|
+
return mapErrorToResponse(error);
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Update an entity
|
|
233
|
+
* @param {string} entityId - Entity ID to update
|
|
234
|
+
* @param {Object} updates - Fields to update
|
|
235
|
+
* @returns {Promise<Object>} Updated entity object
|
|
236
|
+
*/
|
|
237
|
+
async updateEntity(entityId, updates) {
|
|
238
|
+
try {
|
|
239
|
+
if (!entityId) {
|
|
240
|
+
const error = new Error('entityId is required');
|
|
241
|
+
error.code = 'INVALID_ENTITY_DATA';
|
|
242
|
+
throw error;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const entity = await moduleRepo.updateEntity(entityId, updates);
|
|
246
|
+
|
|
247
|
+
if (!entity) {
|
|
248
|
+
const error = new Error(`Entity ${entityId} not found`);
|
|
249
|
+
error.code = 'ENTITY_NOT_FOUND';
|
|
250
|
+
throw error;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return {
|
|
254
|
+
id: entity.id,
|
|
255
|
+
userId: entity.userId,
|
|
256
|
+
externalId: entity.externalId,
|
|
257
|
+
name: entity.name,
|
|
258
|
+
moduleName: entity.moduleName,
|
|
259
|
+
credentialId: entity.credential?._id
|
|
260
|
+
? entity.credential._id.toString()
|
|
261
|
+
: entity.credential,
|
|
262
|
+
};
|
|
263
|
+
} catch (error) {
|
|
264
|
+
return mapErrorToResponse(error);
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Delete an entity
|
|
270
|
+
* @param {string} entityId - Entity ID to delete
|
|
271
|
+
* @returns {Promise<Object>} Result object with success flag
|
|
272
|
+
*/
|
|
273
|
+
async deleteEntity(entityId) {
|
|
274
|
+
try {
|
|
275
|
+
if (!entityId) {
|
|
276
|
+
const error = new Error('entityId is required');
|
|
277
|
+
error.code = 'INVALID_ENTITY_DATA';
|
|
278
|
+
throw error;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
await moduleRepo.deleteEntity(entityId);
|
|
282
|
+
|
|
283
|
+
return { success: true };
|
|
284
|
+
} catch (error) {
|
|
285
|
+
return mapErrorToResponse(error);
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Delete an entity by ID (alias for deleteEntity)
|
|
291
|
+
* @param {string} entityId - Entity ID to delete
|
|
292
|
+
* @returns {Promise<Object>} Result object with success flag
|
|
293
|
+
*/
|
|
294
|
+
async deleteEntityById(entityId) {
|
|
295
|
+
try {
|
|
296
|
+
if (!entityId) {
|
|
297
|
+
const error = new Error('entityId is required');
|
|
298
|
+
error.code = 'INVALID_ENTITY_DATA';
|
|
299
|
+
throw error;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
await moduleRepo.deleteEntity(entityId);
|
|
303
|
+
|
|
304
|
+
return { success: true };
|
|
305
|
+
} catch (error) {
|
|
306
|
+
return mapErrorToResponse(error);
|
|
307
|
+
}
|
|
308
|
+
},
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Remove credential reference from an entity
|
|
312
|
+
* @param {string} entityId - Entity ID to update
|
|
313
|
+
* @returns {Promise<Object>} Result object with success flag
|
|
314
|
+
*/
|
|
315
|
+
async unsetCredential(entityId) {
|
|
316
|
+
try {
|
|
317
|
+
if (!entityId) {
|
|
318
|
+
const error = new Error('entityId is required');
|
|
319
|
+
error.code = 'INVALID_ENTITY_DATA';
|
|
320
|
+
throw error;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const acknowledged = await moduleRepo.unsetCredential(entityId);
|
|
324
|
+
|
|
325
|
+
return { success: acknowledged };
|
|
326
|
+
} catch (error) {
|
|
327
|
+
return mapErrorToResponse(error);
|
|
328
|
+
}
|
|
329
|
+
},
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
module.exports = {
|
|
334
|
+
createEntityCommands,
|
|
335
|
+
ERROR_CODE_MAP,
|
|
336
|
+
};
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
const {
|
|
2
|
+
createIntegrationRepository,
|
|
3
|
+
} = require('../../integrations/repositories/integration-repository-factory');
|
|
4
|
+
const {
|
|
5
|
+
createModuleRepository,
|
|
6
|
+
} = require('../../modules/repositories/module-repository-factory');
|
|
7
|
+
const { ModuleFactory } = require('../../modules/module-factory');
|
|
8
|
+
const {
|
|
9
|
+
LoadIntegrationContextUseCase,
|
|
10
|
+
} = require('../../integrations/use-cases/load-integration-context');
|
|
11
|
+
const {
|
|
12
|
+
FindIntegrationContextByExternalEntityIdUseCase,
|
|
13
|
+
} = require('../../integrations/use-cases/find-integration-context-by-external-entity-id');
|
|
14
|
+
const {
|
|
15
|
+
GetIntegrationsForUser,
|
|
16
|
+
} = require('../../integrations/use-cases/get-integrations-for-user');
|
|
17
|
+
const {
|
|
18
|
+
CreateIntegration,
|
|
19
|
+
} = require('../../integrations/use-cases/create-integration');
|
|
20
|
+
const {
|
|
21
|
+
getModulesDefinitionFromIntegrationClasses,
|
|
22
|
+
} = require('../../integrations/utils/map-integration-dto');
|
|
23
|
+
|
|
24
|
+
const ERROR_CODE_MAP = {
|
|
25
|
+
ENTITY_NOT_FOUND: 401,
|
|
26
|
+
ENTITY_USER_NOT_FOUND: 401,
|
|
27
|
+
INTEGRATION_NOT_FOUND: 404,
|
|
28
|
+
EXTERNAL_ENTITY_ID_REQUIRED: 400,
|
|
29
|
+
INTEGRATION_RECORD_NOT_FOUND: 404,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
function mapErrorToResponse(error) {
|
|
33
|
+
const status = ERROR_CODE_MAP[error?.code] || 500;
|
|
34
|
+
return {
|
|
35
|
+
error: status,
|
|
36
|
+
reason: error?.message,
|
|
37
|
+
code: error?.code,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function createIntegrationCommands({ integrationClass }) {
|
|
42
|
+
if (!integrationClass) {
|
|
43
|
+
throw new Error('integrationClass is required');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Always use Frigg's default repositories and use cases
|
|
47
|
+
const integrationRepository = createIntegrationRepository();
|
|
48
|
+
const moduleRepository = createModuleRepository();
|
|
49
|
+
|
|
50
|
+
const moduleDefinitions = getModulesDefinitionFromIntegrationClasses([
|
|
51
|
+
integrationClass,
|
|
52
|
+
]);
|
|
53
|
+
|
|
54
|
+
const moduleFactory = new ModuleFactory({
|
|
55
|
+
moduleRepository,
|
|
56
|
+
moduleDefinitions,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const loadIntegrationContextUseCase = new LoadIntegrationContextUseCase({
|
|
60
|
+
integrationRepository,
|
|
61
|
+
moduleRepository,
|
|
62
|
+
moduleFactory,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const findByExternalEntityIdUseCase =
|
|
66
|
+
new FindIntegrationContextByExternalEntityIdUseCase({
|
|
67
|
+
integrationRepository,
|
|
68
|
+
moduleRepository,
|
|
69
|
+
loadIntegrationContextUseCase: loadIntegrationContextUseCase,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const getIntegrationsForUserUseCase = new GetIntegrationsForUser({
|
|
73
|
+
integrationRepository,
|
|
74
|
+
integrationClasses: [integrationClass],
|
|
75
|
+
moduleFactory,
|
|
76
|
+
moduleRepository,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const createIntegrationUseCase = new CreateIntegration({
|
|
80
|
+
integrationRepository,
|
|
81
|
+
integrationClasses: [integrationClass],
|
|
82
|
+
moduleFactory,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
async findIntegrationContextByExternalEntityId(externalEntityId) {
|
|
87
|
+
try {
|
|
88
|
+
const { context } = await findByExternalEntityIdUseCase.execute(
|
|
89
|
+
{
|
|
90
|
+
externalEntityId,
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
return { context };
|
|
94
|
+
} catch (error) {
|
|
95
|
+
return mapErrorToResponse(error);
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
async loadIntegrationContextById(integrationId) {
|
|
100
|
+
try {
|
|
101
|
+
const context = await loadIntegrationContextUseCase.execute({
|
|
102
|
+
integrationId,
|
|
103
|
+
});
|
|
104
|
+
return { context };
|
|
105
|
+
} catch (error) {
|
|
106
|
+
return mapErrorToResponse(error);
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Find all integrations for a user
|
|
112
|
+
* @param {string} userId - User ID to search for
|
|
113
|
+
* @returns {Promise<Array>} Array of integration records
|
|
114
|
+
*/
|
|
115
|
+
async findIntegrationsByUserId(userId) {
|
|
116
|
+
try {
|
|
117
|
+
const integrations =
|
|
118
|
+
await getIntegrationsForUserUseCase.execute(userId);
|
|
119
|
+
return integrations;
|
|
120
|
+
} catch (error) {
|
|
121
|
+
return mapErrorToResponse(error);
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Create a new integration
|
|
127
|
+
* @param {Object} params
|
|
128
|
+
* @param {Array<string>} params.entityIds - Array of entity IDs
|
|
129
|
+
* @param {string} params.userId - User ID
|
|
130
|
+
* @param {Object} params.config - Integration configuration (must include type)
|
|
131
|
+
* @returns {Promise<Object>} Created integration object
|
|
132
|
+
*/
|
|
133
|
+
async createIntegration({ entityIds, userId, config }) {
|
|
134
|
+
try {
|
|
135
|
+
const integration = await createIntegrationUseCase.execute(
|
|
136
|
+
entityIds,
|
|
137
|
+
userId,
|
|
138
|
+
config
|
|
139
|
+
);
|
|
140
|
+
return integration;
|
|
141
|
+
} catch (error) {
|
|
142
|
+
return mapErrorToResponse(error);
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Update integration configuration
|
|
148
|
+
* @param {Object} params
|
|
149
|
+
* @param {string} params.integrationId - Integration ID
|
|
150
|
+
* @param {Object} params.config - Updated config object
|
|
151
|
+
* @returns {Promise<Object>} Updated integration
|
|
152
|
+
*/
|
|
153
|
+
async updateIntegrationConfig({ integrationId, config }) {
|
|
154
|
+
try {
|
|
155
|
+
const integration = await integrationRepository.updateIntegrationConfig(
|
|
156
|
+
integrationId,
|
|
157
|
+
config
|
|
158
|
+
);
|
|
159
|
+
return integration;
|
|
160
|
+
} catch (error) {
|
|
161
|
+
return mapErrorToResponse(error);
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Delete an integration by ID
|
|
167
|
+
* @param {string} integrationId - Integration ID to delete
|
|
168
|
+
* @returns {Promise<Object>} Deletion result
|
|
169
|
+
*/
|
|
170
|
+
async deleteIntegrationById(integrationId) {
|
|
171
|
+
try {
|
|
172
|
+
if (!integrationId) {
|
|
173
|
+
const error = new Error('integrationId is required');
|
|
174
|
+
error.code = 'INVALID_INTEGRATION_DATA';
|
|
175
|
+
throw error;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const deleted = await integrationRepository.deleteIntegrationById(integrationId);
|
|
179
|
+
|
|
180
|
+
if (!deleted) {
|
|
181
|
+
const error = new Error(`Integration ${integrationId} not found`);
|
|
182
|
+
error.code = 'INTEGRATION_NOT_FOUND';
|
|
183
|
+
return mapErrorToResponse(error);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
success: true,
|
|
188
|
+
integrationId,
|
|
189
|
+
message: 'Integration deleted successfully',
|
|
190
|
+
};
|
|
191
|
+
} catch (error) {
|
|
192
|
+
return mapErrorToResponse(error);
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async function findIntegrationContextByExternalEntityId({
|
|
199
|
+
integrationClass,
|
|
200
|
+
externalEntityId,
|
|
201
|
+
} = {}) {
|
|
202
|
+
const commands = createIntegrationCommands({ integrationClass });
|
|
203
|
+
|
|
204
|
+
return commands.findIntegrationContextByExternalEntityId(externalEntityId);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
module.exports = {
|
|
208
|
+
createIntegrationCommands,
|
|
209
|
+
findIntegrationContextByExternalEntityId,
|
|
210
|
+
};
|