@friggframework/core 2.0.0-next.5 → 2.0.0-next.51
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 +693 -0
- package/README.md +959 -50
- package/application/commands/README.md +421 -0
- package/application/commands/credential-commands.js +224 -0
- package/application/commands/entity-commands.js +315 -0
- package/application/commands/integration-commands.js +179 -0
- package/application/commands/user-commands.js +213 -0
- package/application/index.js +69 -0
- package/core/CLAUDE.md +690 -0
- package/core/Worker.js +8 -21
- package/core/create-handler.js +2 -7
- package/credential/repositories/credential-repository-factory.js +47 -0
- package/credential/repositories/credential-repository-interface.js +98 -0
- package/credential/repositories/credential-repository-mongo.js +307 -0
- package/credential/repositories/credential-repository-postgres.js +313 -0
- package/credential/repositories/credential-repository.js +302 -0
- package/credential/use-cases/get-credential-for-user.js +21 -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/encryption/README.md +684 -0
- package/database/encryption/encryption-schema-registry.js +141 -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 +25 -12
- package/database/models/WebsocketConnection.js +16 -10
- package/database/models/readme.md +1 -0
- package/database/prisma.js +222 -0
- package/database/repositories/health-check-repository-factory.js +43 -0
- package/database/repositories/health-check-repository-interface.js +87 -0
- package/database/repositories/health-check-repository-mongodb.js +91 -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 +137 -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 +400 -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/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 +22898 -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 +3982 -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 +362 -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 +25072 -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 +3982 -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 +345 -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 +180 -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 +256 -0
- package/handlers/routers/health.js +519 -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 +296 -54
- package/integrations/integration-router.js +381 -182
- package/integrations/options.js +1 -1
- package/integrations/repositories/integration-mapping-repository-factory.js +50 -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-factory.js +44 -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-factory.js +46 -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/dummy-integration-class.js +83 -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 +93 -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-factory.js +33 -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/{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 +59 -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 +55 -0
- package/modules/use-cases/process-authorization-callback.js +122 -0
- package/modules/use-cases/refresh-entity-options.js +59 -0
- package/modules/use-cases/test-module-auth.js +55 -0
- package/modules/utils/map-module-dto.js +18 -0
- package/package.json +82 -50
- package/prisma-mongodb/schema.prisma +362 -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/migration_lock.toml +3 -0
- package/prisma-postgresql/schema.prisma +345 -0
- package/queues/queuer-util.js +28 -15
- package/syncs/manager.js +468 -443
- package/syncs/repositories/sync-repository-factory.js +38 -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-factory.js +33 -0
- package/token/repositories/token-repository-interface.js +131 -0
- package/token/repositories/token-repository-mongo.js +212 -0
- package/token/repositories/token-repository-postgres.js +257 -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-factory.js +46 -0
- package/user/repositories/user-repository-interface.js +198 -0
- package/user/repositories/user-repository-mongo.js +291 -0
- package/user/repositories/user-repository-postgres.js +350 -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 +106 -0
- package/user/use-cases/login-user.js +122 -0
- package/user/user.js +93 -0
- package/utils/backend-path.js +38 -0
- package/utils/index.js +6 -0
- package/websocket/repositories/websocket-connection-repository-factory.js +37 -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/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/api-key.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
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
const { BaseError } = require('./base-error');
|
|
2
|
-
|
|
3
|
-
describe('BaseError', () => {
|
|
4
|
-
it('can be inherited and instantiated', () => {
|
|
5
|
-
class XyzError extends BaseError {}
|
|
6
|
-
const error = new XyzError();
|
|
7
|
-
expect(error).toHaveProperty('message', '');
|
|
8
|
-
expect(error).toHaveProperty('stack');
|
|
9
|
-
expect(error.stack).toContain('XyzError');
|
|
10
|
-
expect(error.stack).toContain('at new XyzError');
|
|
11
|
-
expect(error.stack).toContain('base-error.test.js:');
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it('can set the error message', () => {
|
|
15
|
-
class TestError extends BaseError {}
|
|
16
|
-
const error = new TestError('Goblins!');
|
|
17
|
-
expect(error).toHaveProperty('message', 'Goblins!');
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('sets the error name correctly', () => {
|
|
21
|
-
class TestError extends BaseError {}
|
|
22
|
-
const error = new TestError();
|
|
23
|
-
expect(error).toHaveProperty('name', 'TestError');
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('can set the parent cause', () => {
|
|
27
|
-
class TestError extends BaseError {}
|
|
28
|
-
const rootError = new Error('Davros!');
|
|
29
|
-
const error = new TestError('Daleks!', { cause: rootError });
|
|
30
|
-
expect(error).toHaveProperty('cause', rootError);
|
|
31
|
-
});
|
|
32
|
-
});
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
const fetch = require('node-fetch');
|
|
2
|
-
const { stripIndent } = require('common-tags');
|
|
3
|
-
const { FetchError } = require('./fetch-error');
|
|
4
|
-
const FormData = require('form-data');
|
|
5
|
-
|
|
6
|
-
describe('FetchError', () => {
|
|
7
|
-
it('can be instantiated with default arguments', () => {
|
|
8
|
-
const error = new FetchError();
|
|
9
|
-
expect(error).toHaveProperty('message');
|
|
10
|
-
expect(error).not.toHaveProperty('cause');
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
it('can be created asynchronously with default values', async () => {
|
|
14
|
-
const error = await FetchError.create();
|
|
15
|
-
expect(error).toHaveProperty('message');
|
|
16
|
-
expect(error).not.toHaveProperty('cause');
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('can be created asynchronously', async () => {
|
|
20
|
-
const resource = 'http://example.com';
|
|
21
|
-
const init = {};
|
|
22
|
-
const response = {
|
|
23
|
-
status: 500,
|
|
24
|
-
statusText: 'Space aliens!',
|
|
25
|
-
headers: Object.entries({ 'cache-control': '123' }), // needs to be an Iterable
|
|
26
|
-
text: async () => '<!doctype html>',
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
const error = await FetchError.create({
|
|
30
|
-
resource,
|
|
31
|
-
init,
|
|
32
|
-
response,
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
expect(error).toHaveProperty('message');
|
|
36
|
-
expect(error.message).toContain('GET http://example.com');
|
|
37
|
-
expect(error.message).toContain('500 Space aliens!');
|
|
38
|
-
expect(error.message).toContain('"cache-control": "123"');
|
|
39
|
-
expect(error.message).toContain('<!doctype html>');
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('can be passed an object for the body', async () => {
|
|
43
|
-
const error = new FetchError({ responseBody: { test: true } });
|
|
44
|
-
expect(error).toHaveProperty('message');
|
|
45
|
-
expect(error.message).toContain('"test": true');
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it('ignores response body if already streamed', async () => {
|
|
49
|
-
const response = { bodyUsed: true };
|
|
50
|
-
const error = await FetchError.create({ response });
|
|
51
|
-
|
|
52
|
-
expect(error).toHaveProperty('message');
|
|
53
|
-
expect(error.message).toContain('<response body is unavailable>');
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it.only('prints a formData body legibly', async () => {
|
|
57
|
-
const response = {
|
|
58
|
-
status: 500,
|
|
59
|
-
statusText: 'Space aliens!',
|
|
60
|
-
headers: Object.entries({ 'cache-control': '123' }), // needs to be an Iterable
|
|
61
|
-
text: async () => '<!doctype html>',
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
const params = new URLSearchParams();
|
|
65
|
-
params.append('test', 'test');
|
|
66
|
-
const init = {
|
|
67
|
-
method: 'POST',
|
|
68
|
-
credentials: 'include',
|
|
69
|
-
headers: {},
|
|
70
|
-
query: {},
|
|
71
|
-
body: params,
|
|
72
|
-
returnFullRes: false,
|
|
73
|
-
};
|
|
74
|
-
const error = await FetchError.create({ response, init });
|
|
75
|
-
|
|
76
|
-
expect(error).toHaveProperty('message');
|
|
77
|
-
expect(error.message).toContain('test=test');
|
|
78
|
-
});
|
|
79
|
-
});
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
const { HaltError } = require('./halt-error');
|
|
2
|
-
|
|
3
|
-
describe('HaltError', () => {
|
|
4
|
-
it('can be instantiated', () => {
|
|
5
|
-
const rootError = new Error('Gremlinoids!!');
|
|
6
|
-
const error = new HaltError('STOP', { cause: rootError });
|
|
7
|
-
expect(error).toHaveProperty('message', 'STOP');
|
|
8
|
-
expect(error).toHaveProperty('cause', rootError);
|
|
9
|
-
expect(error).toHaveProperty('isHaltError', true);
|
|
10
|
-
});
|
|
11
|
-
});
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
const {
|
|
2
|
-
RequiredPropertyError,
|
|
3
|
-
ParameterTypeError,
|
|
4
|
-
} = require('./validation-errors');
|
|
5
|
-
|
|
6
|
-
describe('RequiredPropertyError', () => {
|
|
7
|
-
it('can be instantiated with default arguments', () => {
|
|
8
|
-
const error = new RequiredPropertyError();
|
|
9
|
-
expect(error).toHaveProperty(
|
|
10
|
-
'message',
|
|
11
|
-
'Key "" is a required parameter.'
|
|
12
|
-
);
|
|
13
|
-
expect(error).not.toHaveProperty('cause');
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('allows setting the key name of the error', () => {
|
|
17
|
-
const error = new RequiredPropertyError({ key: 'abc' });
|
|
18
|
-
expect(error).toHaveProperty(
|
|
19
|
-
'message',
|
|
20
|
-
'Key "abc" is a required parameter.'
|
|
21
|
-
);
|
|
22
|
-
expect(error).not.toHaveProperty('cause');
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('allows setting the parent of the error', () => {
|
|
26
|
-
const error = new RequiredPropertyError({ parent: class Xyz {} });
|
|
27
|
-
expect(error).toHaveProperty(
|
|
28
|
-
'message',
|
|
29
|
-
'(Xyz) Key "" is a required parameter.'
|
|
30
|
-
);
|
|
31
|
-
expect(error).not.toHaveProperty('cause');
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('passes cause through to the Error parent class', () => {
|
|
35
|
-
const error = new RequiredPropertyError(
|
|
36
|
-
{
|
|
37
|
-
parent: class Qrs {},
|
|
38
|
-
key: 'def',
|
|
39
|
-
},
|
|
40
|
-
{ cause: new Error('Gremlins!!') }
|
|
41
|
-
);
|
|
42
|
-
const expectedMessage = '(Qrs) Key "def" is a required parameter.';
|
|
43
|
-
expect(error).toHaveProperty('message', expectedMessage);
|
|
44
|
-
expect(error).toHaveProperty('cause');
|
|
45
|
-
expect(error.cause).toHaveProperty('message', 'Gremlins!!');
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
describe('ParameterTypeError', () => {
|
|
50
|
-
it('can be instantiated with default arguments', () => {
|
|
51
|
-
const error = new ParameterTypeError();
|
|
52
|
-
expect(error).toHaveProperty(
|
|
53
|
-
'message',
|
|
54
|
-
'Expected value "" to be of type ""'
|
|
55
|
-
);
|
|
56
|
-
expect(error).not.toHaveProperty('cause');
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('allows setting the key name of the error', () => {
|
|
60
|
-
const error = new ParameterTypeError({ key: 'abc' });
|
|
61
|
-
expect(error).toHaveProperty(
|
|
62
|
-
'message',
|
|
63
|
-
'Expected key "abc" with value "" to be of type ""'
|
|
64
|
-
);
|
|
65
|
-
expect(error).not.toHaveProperty('cause');
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it('allows setting the parent of the error', () => {
|
|
69
|
-
const error = new ParameterTypeError({ parent: class Xyz {} });
|
|
70
|
-
expect(error).toHaveProperty(
|
|
71
|
-
'message',
|
|
72
|
-
'(Xyz) Expected value "" to be of type ""'
|
|
73
|
-
);
|
|
74
|
-
expect(error).not.toHaveProperty('cause');
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('allows setting the value of the error', () => {
|
|
78
|
-
const error = new ParameterTypeError({ value: 1 });
|
|
79
|
-
expect(error).toHaveProperty(
|
|
80
|
-
'message',
|
|
81
|
-
'Expected value "1" to be of type ""'
|
|
82
|
-
);
|
|
83
|
-
expect(error).not.toHaveProperty('cause');
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it('allows setting the expected type of the error', () => {
|
|
87
|
-
const error = new ParameterTypeError({ expectedType: class Xyz {} });
|
|
88
|
-
expect(error).toHaveProperty(
|
|
89
|
-
'message',
|
|
90
|
-
'Expected value "" to be of type "Xyz"'
|
|
91
|
-
);
|
|
92
|
-
expect(error).not.toHaveProperty('cause');
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it('allows setting the expected type of the error to Array', () => {
|
|
96
|
-
const error = new ParameterTypeError({ expectedType: Array });
|
|
97
|
-
expect(error).toHaveProperty(
|
|
98
|
-
'message',
|
|
99
|
-
'Expected value "" to be of type "Array"'
|
|
100
|
-
);
|
|
101
|
-
expect(error).not.toHaveProperty('cause');
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it('passes cause through to the Error parent class', () => {
|
|
105
|
-
const rootError = new Error('Gremlins!!');
|
|
106
|
-
const error = new ParameterTypeError(
|
|
107
|
-
{
|
|
108
|
-
parent: class Parent {},
|
|
109
|
-
key: 'clé',
|
|
110
|
-
expectedType: class Expected {},
|
|
111
|
-
value: 'schmalue',
|
|
112
|
-
},
|
|
113
|
-
{ cause: rootError }
|
|
114
|
-
);
|
|
115
|
-
const expectedMessage =
|
|
116
|
-
'(Parent) Expected key "clé" with value "schmalue" to be of type "Expected"';
|
|
117
|
-
expect(error).toHaveProperty('message', expectedMessage);
|
|
118
|
-
expect(error).toHaveProperty('cause', rootError);
|
|
119
|
-
});
|
|
120
|
-
});
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
const {IntegrationFactory, IntegrationHelper} = require('./integration-factory');
|
|
2
|
-
const User = require('./integration-user');
|
|
3
|
-
|
|
4
|
-
function createFriggBackend(appDefinition) {
|
|
5
|
-
const {integrations = [], user=null} = appDefinition
|
|
6
|
-
const integrationFactory = new IntegrationFactory(integrations);
|
|
7
|
-
if (user) {
|
|
8
|
-
if (user.usePassword) {
|
|
9
|
-
User.usePassword = true;
|
|
10
|
-
}
|
|
11
|
-
if (user.primary === 'organization') {
|
|
12
|
-
User.primary = User.OrganizationUser
|
|
13
|
-
}
|
|
14
|
-
if (user.individualUserRequired !== undefined) {
|
|
15
|
-
User.individualUserRequired = user.individualUserRequired
|
|
16
|
-
}
|
|
17
|
-
if (user.organizationUserRequired !== undefined) {
|
|
18
|
-
User.organizationUserRequired = user.organizationUserRequired
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
const backend = {
|
|
23
|
-
integrationFactory,
|
|
24
|
-
moduleFactory: integrationFactory.moduleFactory,
|
|
25
|
-
IntegrationHelper,
|
|
26
|
-
User: User
|
|
27
|
-
}
|
|
28
|
-
return backend
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
module.exports = { createFriggBackend }
|
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
const { ModuleFactory, Credential, Entity } = require('../module-plugin');
|
|
2
|
-
const { IntegrationModel } = require('./integration-model');
|
|
3
|
-
const _ = require('lodash');
|
|
4
|
-
|
|
5
|
-
class IntegrationFactory {
|
|
6
|
-
constructor(integrationClasses = []) {
|
|
7
|
-
this.integrationClasses = integrationClasses;
|
|
8
|
-
this.moduleFactory = new ModuleFactory(...this.getModules());
|
|
9
|
-
this.integrationTypes = this.integrationClasses.map(
|
|
10
|
-
(IntegrationClass) => IntegrationClass.getName()
|
|
11
|
-
);
|
|
12
|
-
this.getIntegrationDefinitions = this.integrationClasses.map(
|
|
13
|
-
(IntegrationClass) => IntegrationClass.Definition
|
|
14
|
-
);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
async getIntegrationOptions() {
|
|
18
|
-
const options = this.integrationClasses.map(
|
|
19
|
-
(IntegrationClass) => IntegrationClass
|
|
20
|
-
);
|
|
21
|
-
return {
|
|
22
|
-
entities: {
|
|
23
|
-
options: options.map((IntegrationClass) =>
|
|
24
|
-
IntegrationClass.getOptionDetails()
|
|
25
|
-
),
|
|
26
|
-
authorized: [],
|
|
27
|
-
},
|
|
28
|
-
integrations: [],
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
getModules() {
|
|
33
|
-
return [
|
|
34
|
-
...new Set(
|
|
35
|
-
this.integrationClasses
|
|
36
|
-
.map((integration) =>
|
|
37
|
-
Object.values(integration.Definition.modules).map(
|
|
38
|
-
(module) => module.definition
|
|
39
|
-
)
|
|
40
|
-
)
|
|
41
|
-
.flat()
|
|
42
|
-
),
|
|
43
|
-
];
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
getIntegrationClassByType(type) {
|
|
47
|
-
const integrationClassIndex = this.integrationTypes.indexOf(type);
|
|
48
|
-
return this.integrationClasses[integrationClassIndex];
|
|
49
|
-
}
|
|
50
|
-
getModuleTypesAndKeys(integrationClass) {
|
|
51
|
-
const moduleTypesAndKeys = {};
|
|
52
|
-
const moduleTypeCount = {};
|
|
53
|
-
|
|
54
|
-
if (integrationClass && integrationClass.Definition.modules) {
|
|
55
|
-
for (const [key, moduleClass] of Object.entries(
|
|
56
|
-
integrationClass.Definition.modules
|
|
57
|
-
)) {
|
|
58
|
-
if (
|
|
59
|
-
moduleClass &&
|
|
60
|
-
typeof moduleClass.definition.getName === 'function'
|
|
61
|
-
) {
|
|
62
|
-
const moduleType = moduleClass.definition.getName();
|
|
63
|
-
|
|
64
|
-
// Check if this module type has already been seen
|
|
65
|
-
if (moduleType in moduleTypesAndKeys) {
|
|
66
|
-
throw new Error(
|
|
67
|
-
`Duplicate module type "${moduleType}" found in integration class definition.`
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Well how baout now
|
|
72
|
-
|
|
73
|
-
moduleTypesAndKeys[moduleType] = key;
|
|
74
|
-
moduleTypeCount[moduleType] =
|
|
75
|
-
(moduleTypeCount[moduleType] || 0) + 1;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Check for any module types with count > 1
|
|
81
|
-
for (const [moduleType, count] of Object.entries(moduleTypeCount)) {
|
|
82
|
-
if (count > 1) {
|
|
83
|
-
throw new Error(
|
|
84
|
-
`Multiple instances of module type "${moduleType}" found in integration class definition.`
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return moduleTypesAndKeys;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
async getInstanceFromIntegrationId(params) {
|
|
93
|
-
const integrationRecord = await IntegrationHelper.getIntegrationById(
|
|
94
|
-
params.integrationId
|
|
95
|
-
);
|
|
96
|
-
let { userId } = params;
|
|
97
|
-
if (!integrationRecord) {
|
|
98
|
-
throw new Error(
|
|
99
|
-
`No integration found by the ID of ${params.integrationId}`
|
|
100
|
-
);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (!userId) {
|
|
104
|
-
userId = integrationRecord.user._id.toString();
|
|
105
|
-
} else if (userId.toString() !== integrationRecord.user.toString()) {
|
|
106
|
-
throw new Error(
|
|
107
|
-
`Integration ${
|
|
108
|
-
params.integrationId
|
|
109
|
-
} does not belong to User ${userId}, ${integrationRecord.user.toString()}`
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const integrationClass = this.getIntegrationClassByType(
|
|
114
|
-
integrationRecord.config.type
|
|
115
|
-
);
|
|
116
|
-
|
|
117
|
-
const instance = new integrationClass({
|
|
118
|
-
userId,
|
|
119
|
-
integrationId: params.integrationId,
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
if (
|
|
123
|
-
integrationRecord.entityReference &&
|
|
124
|
-
Object.keys(integrationRecord.entityReference) > 0
|
|
125
|
-
) {
|
|
126
|
-
// Use the specified entityReference to find the modules and load them according to their key
|
|
127
|
-
// entityReference will be a map of entityIds with their corresponding desired key
|
|
128
|
-
for (const [entityId, key] of Object.entries(
|
|
129
|
-
integrationRecord.entityReference
|
|
130
|
-
)) {
|
|
131
|
-
const moduleInstance =
|
|
132
|
-
await this.moduleFactory.getModuleInstanceFromEntityId(
|
|
133
|
-
entityId,
|
|
134
|
-
integrationRecord.user
|
|
135
|
-
);
|
|
136
|
-
instance[key] = moduleInstance;
|
|
137
|
-
}
|
|
138
|
-
} else {
|
|
139
|
-
// for each entity, get the moduleinstance and load them according to their keys
|
|
140
|
-
// If it's the first entity, load the moduleinstance into primary as well
|
|
141
|
-
// If it's the second entity, load the moduleinstance into target as well
|
|
142
|
-
const moduleTypesAndKeys =
|
|
143
|
-
this.getModuleTypesAndKeys(integrationClass);
|
|
144
|
-
for (let i = 0; i < integrationRecord.entities.length; i++) {
|
|
145
|
-
const entityId = integrationRecord.entities[i];
|
|
146
|
-
const moduleInstance =
|
|
147
|
-
await this.moduleFactory.getModuleInstanceFromEntityId(
|
|
148
|
-
entityId,
|
|
149
|
-
integrationRecord.user
|
|
150
|
-
);
|
|
151
|
-
const moduleType = moduleInstance.getName();
|
|
152
|
-
const key = moduleTypesAndKeys[moduleType];
|
|
153
|
-
instance[key] = moduleInstance;
|
|
154
|
-
if (i === 0) {
|
|
155
|
-
instance.primary = moduleInstance;
|
|
156
|
-
} else if (i === 1) {
|
|
157
|
-
instance.target = moduleInstance;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
instance.record = integrationRecord;
|
|
162
|
-
|
|
163
|
-
try {
|
|
164
|
-
const additionalUserActions =
|
|
165
|
-
await instance.loadDynamicUserActions();
|
|
166
|
-
instance.events = { ...instance.events, ...additionalUserActions };
|
|
167
|
-
} catch (e) {
|
|
168
|
-
instance.record.status = 'ERROR';
|
|
169
|
-
instance.record.messages.errors.push(e);
|
|
170
|
-
await instance.record.save();
|
|
171
|
-
}
|
|
172
|
-
// Register all of the event handlers
|
|
173
|
-
|
|
174
|
-
await instance.registerEventHandlers();
|
|
175
|
-
return instance;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
async createIntegration(entities, userId, config) {
|
|
179
|
-
const integrationRecord = await IntegrationModel.create({
|
|
180
|
-
entities: entities,
|
|
181
|
-
user: userId,
|
|
182
|
-
config,
|
|
183
|
-
version: '0.0.0',
|
|
184
|
-
});
|
|
185
|
-
return await this.getInstanceFromIntegrationId({
|
|
186
|
-
integrationId: integrationRecord.id,
|
|
187
|
-
userId,
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
const IntegrationHelper = {
|
|
193
|
-
getFormattedIntegration: async function (integrationRecord) {
|
|
194
|
-
const integrationObj = {
|
|
195
|
-
id: integrationRecord.id,
|
|
196
|
-
status: integrationRecord.status,
|
|
197
|
-
config: integrationRecord.config,
|
|
198
|
-
entities: [],
|
|
199
|
-
version: integrationRecord.version,
|
|
200
|
-
messages: integrationRecord.messages,
|
|
201
|
-
};
|
|
202
|
-
for (const entityId of integrationRecord.entities) {
|
|
203
|
-
// Only return non-internal fields. Leverages "select" and "options" to non-excepted fields and a pure object.
|
|
204
|
-
const entity = await Entity.findById(
|
|
205
|
-
entityId,
|
|
206
|
-
'-createdAt -updatedAt -user -credentials -credential -_id -__t -__v',
|
|
207
|
-
{ lean: true }
|
|
208
|
-
);
|
|
209
|
-
integrationObj.entities.push({
|
|
210
|
-
id: entityId,
|
|
211
|
-
...entity,
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
return integrationObj;
|
|
215
|
-
},
|
|
216
|
-
|
|
217
|
-
getIntegrationsForUserId: async function (userId) {
|
|
218
|
-
const integrationList = await IntegrationModel.find({ user: userId });
|
|
219
|
-
return await Promise.all(
|
|
220
|
-
integrationList.map(
|
|
221
|
-
async (integrationRecord) =>
|
|
222
|
-
await IntegrationHelper.getFormattedIntegration(
|
|
223
|
-
integrationRecord
|
|
224
|
-
)
|
|
225
|
-
)
|
|
226
|
-
);
|
|
227
|
-
},
|
|
228
|
-
|
|
229
|
-
deleteIntegrationForUserById: async function (userId, integrationId) {
|
|
230
|
-
const integrationList = await IntegrationModel.find({
|
|
231
|
-
user: userId,
|
|
232
|
-
_id: integrationId,
|
|
233
|
-
});
|
|
234
|
-
if (integrationList.length !== 1) {
|
|
235
|
-
throw new Error(
|
|
236
|
-
`Integration with id of ${integrationId} does not exist for this user`
|
|
237
|
-
);
|
|
238
|
-
}
|
|
239
|
-
await IntegrationModel.deleteOne({ _id: integrationId });
|
|
240
|
-
},
|
|
241
|
-
|
|
242
|
-
getIntegrationById: async function (id) {
|
|
243
|
-
return IntegrationModel.findById(id).populate('entities');
|
|
244
|
-
},
|
|
245
|
-
|
|
246
|
-
listCredentials: async function (options) {
|
|
247
|
-
return Credential.find(options);
|
|
248
|
-
},
|
|
249
|
-
};
|
|
250
|
-
|
|
251
|
-
module.exports = { IntegrationFactory, IntegrationHelper };
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
const { mongoose } = require('../database/mongoose');
|
|
2
|
-
const { Encrypt } = require('../encrypt');
|
|
3
|
-
|
|
4
|
-
const schema = new mongoose.Schema(
|
|
5
|
-
{
|
|
6
|
-
integration: {
|
|
7
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
8
|
-
ref: 'Integration',
|
|
9
|
-
required: true,
|
|
10
|
-
},
|
|
11
|
-
sourceId: { type: String }, // Used for lookups
|
|
12
|
-
mapping: {}
|
|
13
|
-
},
|
|
14
|
-
{ timestamps: true }
|
|
15
|
-
);
|
|
16
|
-
|
|
17
|
-
schema.plugin(Encrypt);
|
|
18
|
-
|
|
19
|
-
schema.static({
|
|
20
|
-
findBy: async function (integrationId, sourceId) {
|
|
21
|
-
const mappings = await this.find({ integration: integrationId, sourceId });
|
|
22
|
-
if (mappings.length === 0) {
|
|
23
|
-
return null;
|
|
24
|
-
} else if (mappings.length === 1) {
|
|
25
|
-
return mappings[0].mapping;
|
|
26
|
-
} else {
|
|
27
|
-
throw new Error('multiple integration mappings with same sourceId');
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
upsert: async function (integrationId, sourceId, mapping) {
|
|
31
|
-
return this.findOneAndUpdate(
|
|
32
|
-
{ integration: integrationId, sourceId },
|
|
33
|
-
{ mapping },
|
|
34
|
-
{ new: true, upsert: true, setDefaultsOnInsert: true }
|
|
35
|
-
);
|
|
36
|
-
},
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
schema.index({ integration: 1, sourceId: 1 });
|
|
40
|
-
|
|
41
|
-
const IntegrationMapping =
|
|
42
|
-
mongoose.models.IntegrationMapping || mongoose.model('IntegrationMapping', schema);
|
|
43
|
-
module.exports = { IntegrationMapping };
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
const { mongoose } = require('../database/mongoose');
|
|
2
|
-
|
|
3
|
-
const schema = new mongoose.Schema(
|
|
4
|
-
{
|
|
5
|
-
entities: [
|
|
6
|
-
{
|
|
7
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
8
|
-
ref: 'Entity',
|
|
9
|
-
required: true,
|
|
10
|
-
},
|
|
11
|
-
],
|
|
12
|
-
entityReference: {
|
|
13
|
-
type: mongoose.Schema.Types.Map,
|
|
14
|
-
of: String,
|
|
15
|
-
},
|
|
16
|
-
user: {
|
|
17
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
18
|
-
ref: 'User',
|
|
19
|
-
required: false,
|
|
20
|
-
},
|
|
21
|
-
status: {
|
|
22
|
-
type: String,
|
|
23
|
-
enum: [
|
|
24
|
-
'ENABLED',
|
|
25
|
-
'NEEDS_CONFIG',
|
|
26
|
-
'PROCESSING',
|
|
27
|
-
'DISABLED',
|
|
28
|
-
'ERROR',
|
|
29
|
-
],
|
|
30
|
-
default: 'ENABLED',
|
|
31
|
-
},
|
|
32
|
-
config: {},
|
|
33
|
-
version: { type: String },
|
|
34
|
-
messages: {
|
|
35
|
-
errors: [],
|
|
36
|
-
warnings: [],
|
|
37
|
-
info: [],
|
|
38
|
-
logs: [],
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
{ timestamps: true }
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
const Integration =
|
|
45
|
-
mongoose.models.Integration || mongoose.model('Integration', schema);
|
|
46
|
-
module.exports = { IntegrationModel: Integration };
|