@friggframework/core 2.0.0--canary.461.61382d8.0 → 2.0.0--canary.461.5767fa4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/generated/prisma-mongodb/client.d.ts +1 -0
  2. package/generated/prisma-mongodb/client.js +4 -0
  3. package/generated/prisma-mongodb/default.d.ts +1 -0
  4. package/generated/prisma-mongodb/default.js +4 -0
  5. package/generated/prisma-mongodb/edge.d.ts +1 -0
  6. package/generated/prisma-mongodb/edge.js +336 -0
  7. package/generated/prisma-mongodb/index-browser.js +318 -0
  8. package/generated/prisma-mongodb/index.d.ts +22993 -0
  9. package/generated/prisma-mongodb/index.js +361 -0
  10. package/generated/prisma-mongodb/package.json +183 -0
  11. package/generated/prisma-mongodb/query-engine-debian-openssl-3.0.x +0 -0
  12. package/generated/prisma-mongodb/query-engine-rhel-openssl-3.0.x +0 -0
  13. package/generated/prisma-mongodb/runtime/binary.d.ts +1 -0
  14. package/generated/prisma-mongodb/runtime/binary.js +289 -0
  15. package/generated/prisma-mongodb/runtime/edge-esm.js +34 -0
  16. package/generated/prisma-mongodb/runtime/edge.js +34 -0
  17. package/generated/prisma-mongodb/runtime/index-browser.d.ts +370 -0
  18. package/generated/prisma-mongodb/runtime/index-browser.js +16 -0
  19. package/generated/prisma-mongodb/runtime/library.d.ts +3977 -0
  20. package/generated/prisma-mongodb/runtime/react-native.js +83 -0
  21. package/generated/prisma-mongodb/runtime/wasm-compiler-edge.js +84 -0
  22. package/generated/prisma-mongodb/runtime/wasm-engine-edge.js +36 -0
  23. package/generated/prisma-mongodb/schema.prisma +364 -0
  24. package/generated/prisma-mongodb/wasm-edge-light-loader.mjs +4 -0
  25. package/generated/prisma-mongodb/wasm-worker-loader.mjs +4 -0
  26. package/generated/prisma-mongodb/wasm.d.ts +1 -0
  27. package/generated/prisma-mongodb/wasm.js +343 -0
  28. package/generated/prisma-postgresql/client.d.ts +1 -0
  29. package/generated/prisma-postgresql/client.js +4 -0
  30. package/generated/prisma-postgresql/default.d.ts +1 -0
  31. package/generated/prisma-postgresql/default.js +4 -0
  32. package/generated/prisma-postgresql/edge.d.ts +1 -0
  33. package/generated/prisma-postgresql/edge.js +358 -0
  34. package/generated/prisma-postgresql/index-browser.js +340 -0
  35. package/generated/prisma-postgresql/index.d.ts +25171 -0
  36. package/generated/prisma-postgresql/index.js +383 -0
  37. package/generated/prisma-postgresql/package.json +183 -0
  38. package/generated/prisma-postgresql/query-engine-debian-openssl-3.0.x +0 -0
  39. package/generated/prisma-postgresql/query-engine-rhel-openssl-3.0.x +0 -0
  40. package/generated/prisma-postgresql/query_engine_bg.js +2 -0
  41. package/generated/prisma-postgresql/query_engine_bg.wasm +0 -0
  42. package/generated/prisma-postgresql/runtime/binary.d.ts +1 -0
  43. package/generated/prisma-postgresql/runtime/binary.js +289 -0
  44. package/generated/prisma-postgresql/runtime/edge-esm.js +34 -0
  45. package/generated/prisma-postgresql/runtime/edge.js +34 -0
  46. package/generated/prisma-postgresql/runtime/index-browser.d.ts +370 -0
  47. package/generated/prisma-postgresql/runtime/index-browser.js +16 -0
  48. package/generated/prisma-postgresql/runtime/library.d.ts +3977 -0
  49. package/generated/prisma-postgresql/runtime/react-native.js +83 -0
  50. package/generated/prisma-postgresql/runtime/wasm-compiler-edge.js +84 -0
  51. package/generated/prisma-postgresql/runtime/wasm-engine-edge.js +36 -0
  52. package/generated/prisma-postgresql/schema.prisma +347 -0
  53. package/generated/prisma-postgresql/wasm-edge-light-loader.mjs +4 -0
  54. package/generated/prisma-postgresql/wasm-worker-loader.mjs +4 -0
  55. package/generated/prisma-postgresql/wasm.d.ts +1 -0
  56. package/generated/prisma-postgresql/wasm.js +365 -0
  57. package/package.json +5 -5
  58. package/application/commands/integration-commands.test.js +0 -123
  59. package/core/Worker.test.js +0 -159
  60. package/database/encryption/encryption-integration.test.js +0 -553
  61. package/database/encryption/encryption-schema-registry.test.js +0 -392
  62. package/database/encryption/field-encryption-service.test.js +0 -525
  63. package/database/encryption/mongo-decryption-fix-verification.test.js +0 -348
  64. package/database/encryption/postgres-decryption-fix-verification.test.js +0 -371
  65. package/database/encryption/postgres-relation-decryption.test.js +0 -245
  66. package/database/encryption/prisma-encryption-extension.test.js +0 -439
  67. package/database/repositories/migration-status-repository-s3.test.js +0 -158
  68. package/database/use-cases/check-encryption-health-use-case.test.js +0 -192
  69. package/database/use-cases/get-migration-status-use-case.test.js +0 -171
  70. package/database/use-cases/run-database-migration-use-case.test.js +0 -310
  71. package/database/use-cases/trigger-database-migration-use-case.test.js +0 -250
  72. package/database/utils/prisma-runner.test.js +0 -486
  73. package/encrypt/Cryptor.test.js +0 -144
  74. package/errors/base-error.test.js +0 -32
  75. package/errors/fetch-error.test.js +0 -79
  76. package/errors/halt-error.test.js +0 -11
  77. package/errors/validation-errors.test.js +0 -120
  78. package/handlers/auth-flow.integration.test.js +0 -147
  79. package/handlers/integration-event-dispatcher.test.js +0 -209
  80. package/handlers/routers/db-migration.test.js +0 -51
  81. package/handlers/routers/health.test.js +0 -210
  82. package/handlers/routers/integration-webhook-routers.test.js +0 -126
  83. package/handlers/use-cases/check-integrations-health-use-case.test.js +0 -125
  84. package/handlers/webhook-flow.integration.test.js +0 -356
  85. package/handlers/workers/db-migration.test.js +0 -50
  86. package/handlers/workers/integration-defined-workers.test.js +0 -184
  87. package/integrations/tests/integration-router-multi-auth.test.js +0 -369
  88. package/integrations/tests/use-cases/create-integration.test.js +0 -131
  89. package/integrations/tests/use-cases/delete-integration-for-user.test.js +0 -150
  90. package/integrations/tests/use-cases/find-integration-context-by-external-entity-id.test.js +0 -92
  91. package/integrations/tests/use-cases/get-integration-for-user.test.js +0 -150
  92. package/integrations/tests/use-cases/get-integration-instance.test.js +0 -176
  93. package/integrations/tests/use-cases/get-integrations-for-user.test.js +0 -176
  94. package/integrations/tests/use-cases/get-possible-integrations.test.js +0 -188
  95. package/integrations/tests/use-cases/update-integration-messages.test.js +0 -142
  96. package/integrations/tests/use-cases/update-integration-status.test.js +0 -103
  97. package/integrations/tests/use-cases/update-integration.test.js +0 -141
  98. package/integrations/use-cases/create-process.test.js +0 -178
  99. package/integrations/use-cases/get-process.test.js +0 -190
  100. package/integrations/use-cases/load-integration-context-full.test.js +0 -329
  101. package/integrations/use-cases/load-integration-context.test.js +0 -114
  102. package/integrations/use-cases/update-process-metrics.test.js +0 -308
  103. package/integrations/use-cases/update-process-state.test.js +0 -256
  104. package/lambda/TimeoutCatcher.test.js +0 -68
  105. package/logs/logger.test.js +0 -76
  106. package/modules/module-hydration.test.js +0 -205
  107. package/modules/requester/requester.test.js +0 -28
  108. package/queues/queuer-util.test.js +0 -132
  109. package/user/tests/use-cases/create-individual-user.test.js +0 -24
  110. package/user/tests/use-cases/create-organization-user.test.js +0 -28
  111. package/user/tests/use-cases/create-token-for-user-id.test.js +0 -19
  112. package/user/tests/use-cases/get-user-from-adopter-jwt.test.js +0 -113
  113. package/user/tests/use-cases/get-user-from-bearer-token.test.js +0 -64
  114. package/user/tests/use-cases/get-user-from-x-frigg-headers.test.js +0 -346
  115. package/user/tests/use-cases/login-user.test.js +0 -220
  116. package/user/tests/user-password-encryption-isolation.test.js +0 -237
  117. package/user/tests/user-password-hashing.test.js +0 -235
  118. package/websocket/repositories/websocket-connection-repository.test.js +0 -227
@@ -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,147 +0,0 @@
1
- jest.mock('../database/config', () => ({
2
- DB_TYPE: 'mongodb',
3
- getDatabaseType: jest.fn(() => 'mongodb'),
4
- PRISMA_LOG_LEVEL: 'error,warn',
5
- PRISMA_QUERY_LOGGING: false,
6
- }));
7
-
8
- const { IntegrationEventDispatcher } = require('./integration-event-dispatcher');
9
- const { IntegrationBase } = require('../integrations/integration-base');
10
-
11
- class SimulatedAsanaIntegration extends IntegrationBase {
12
- static Definition = {
13
- name: 'asana',
14
- version: '1.0.0',
15
- modules: {},
16
- routes: [
17
- { path: '/auth', method: 'GET', event: 'AUTH_REQUEST' },
18
- { path: '/auth/redirect/:provider', method: 'GET', event: 'AUTH_REDIRECT' },
19
- { path: '/form', method: 'GET', event: 'LOAD_FORM' },
20
- ],
21
- };
22
-
23
- constructor(params = {}) {
24
- super(params);
25
- this.events = {
26
- AUTH_REQUEST: { handler: this.authRequest.bind(this) },
27
- AUTH_REDIRECT: { handler: this.authRedirect.bind(this) },
28
- LOAD_FORM: { handler: this.loadForm.bind(this) },
29
- };
30
- }
31
-
32
- async authRequest() {
33
- return {
34
- success: true,
35
- action: 'redirect',
36
- hydrated: this.isHydrated,
37
- };
38
- }
39
-
40
- async authRedirect({ req }) {
41
- const { code } = req.query || {};
42
- return {
43
- success: true,
44
- action: 'tokens_received',
45
- receivedCode: code,
46
- hydrated: this.isHydrated,
47
- };
48
- }
49
-
50
- async loadForm() {
51
- if (!this.isHydrated && SimulatedAsanaIntegration.testRecord) {
52
- this.setIntegrationRecord({
53
- record: SimulatedAsanaIntegration.testRecord.record,
54
- modules: SimulatedAsanaIntegration.testRecord.modules,
55
- });
56
- }
57
-
58
- this.assertHydrated('Integration not found - must authenticate first');
59
-
60
- return {
61
- success: true,
62
- form: {
63
- fields: ['field1', 'field2'],
64
- },
65
- integrationId: this.id,
66
- };
67
- }
68
- }
69
-
70
- describe('IntegrationEventDispatcher auth flow', () => {
71
- const createDispatcher = () =>
72
- new IntegrationEventDispatcher(new SimulatedAsanaIntegration());
73
-
74
- beforeEach(() => {
75
- SimulatedAsanaIntegration.testRecord = null;
76
- });
77
-
78
- it('handles auth request without hydration', async () => {
79
- const dispatcher = createDispatcher();
80
- const result = await dispatcher.dispatchHttp({
81
- event: 'AUTH_REQUEST',
82
- req: { params: { provider: 'asana' }, query: {} },
83
- res: {},
84
- next: jest.fn(),
85
- });
86
-
87
- expect(result).toEqual({ success: true, action: 'redirect', hydrated: false });
88
- });
89
-
90
- it('handles auth redirect without hydration', async () => {
91
- const dispatcher = createDispatcher();
92
- const result = await dispatcher.dispatchHttp({
93
- event: 'AUTH_REDIRECT',
94
- req: { params: { provider: 'asana' }, query: { code: 'abc123' } },
95
- res: {},
96
- next: jest.fn(),
97
- });
98
-
99
- expect(result).toEqual({
100
- success: true,
101
- action: 'tokens_received',
102
- receivedCode: 'abc123',
103
- hydrated: false,
104
- });
105
- });
106
-
107
- it('throws for protected routes when no record is loaded', async () => {
108
- const dispatcher = createDispatcher();
109
- await expect(
110
- dispatcher.dispatchHttp({
111
- event: 'LOAD_FORM',
112
- req: { query: {} },
113
- res: {},
114
- next: jest.fn(),
115
- })
116
- ).rejects.toThrow('Integration not found - must authenticate first');
117
- });
118
-
119
- it('allows handlers to hydrate explicitly before continuing', async () => {
120
- SimulatedAsanaIntegration.testRecord = {
121
- record: {
122
- id: 'integration-123',
123
- userId: 'user-456',
124
- config: { type: 'asana' },
125
- status: 'ENABLED',
126
- version: '1.0.0',
127
- messages: { errors: [], warnings: [] },
128
- entities: [],
129
- },
130
- modules: [],
131
- };
132
-
133
- const dispatcher = createDispatcher();
134
- const result = await dispatcher.dispatchHttp({
135
- event: 'LOAD_FORM',
136
- req: { query: {} },
137
- res: {},
138
- next: jest.fn(),
139
- });
140
-
141
- expect(result).toEqual({
142
- success: true,
143
- form: { fields: ['field1', 'field2'] },
144
- integrationId: 'integration-123',
145
- });
146
- });
147
- });
@@ -1,209 +0,0 @@
1
- jest.mock('../database/config', () => ({
2
- DB_TYPE: 'mongodb',
3
- getDatabaseType: jest.fn(() => 'mongodb'),
4
- PRISMA_LOG_LEVEL: 'error,warn',
5
- PRISMA_QUERY_LOGGING: false,
6
- }));
7
-
8
- const { IntegrationEventDispatcher } = require('./integration-event-dispatcher');
9
- const { IntegrationBase } = require('../integrations/integration-base');
10
-
11
- class TestIntegration extends IntegrationBase {
12
- static Definition = {
13
- name: 'test-integration',
14
- version: '1.0.0',
15
- modules: {},
16
- routes: [
17
- { path: '/auth', method: 'GET', event: 'AUTH_REQUEST' },
18
- { path: '/data', method: 'GET', event: 'LOAD_DATA' },
19
- { path: '/job', method: 'POST', event: 'TEST_EVENT' },
20
- { path: '/dynamic', method: 'GET', event: 'DYNAMIC_EVENT' },
21
- ],
22
- };
23
-
24
- constructor(params) {
25
- super(params);
26
- this.events = {
27
- AUTH_REQUEST: { handler: this.authRequest.bind(this) },
28
- LOAD_DATA: { handler: this.loadData.bind(this) },
29
- TEST_EVENT: { handler: this.testHandler.bind(this) },
30
- };
31
- }
32
-
33
- async authRequest() {
34
- TestIntegration.latestInstance = this;
35
- return {
36
- success: true,
37
- hydrated: this.isHydrated,
38
- };
39
- }
40
-
41
- async loadData() {
42
- this.assertHydrated('loadData requires hydration');
43
- return { success: true };
44
- }
45
-
46
- async testHandler({ data }) {
47
- TestIntegration.latestInstance = this;
48
- return { received: data };
49
- }
50
-
51
- async initialize() {
52
- this.events = {
53
- ...this.events,
54
- DYNAMIC_EVENT: { handler: this.dynamicHandler.bind(this) },
55
- };
56
- }
57
-
58
- async dynamicHandler() {
59
- TestIntegration.latestInstance = this;
60
- return { dynamic: true };
61
- }
62
- }
63
-
64
- describe('IntegrationEventDispatcher', () => {
65
- const createDispatcher = () =>
66
- new IntegrationEventDispatcher(new TestIntegration());
67
-
68
- beforeEach(() => {
69
- TestIntegration.latestInstance = null;
70
- });
71
-
72
- describe('dispatchHttp', () => {
73
- it('creates a stateless integration instance for HTTP events', async () => {
74
- const dispatcher = createDispatcher();
75
- const result = await dispatcher.dispatchHttp({
76
- event: 'AUTH_REQUEST',
77
- req: {},
78
- res: {},
79
- next: jest.fn(),
80
- });
81
-
82
- expect(result).toEqual({ success: true, hydrated: false });
83
- expect(TestIntegration.latestInstance).toBeInstanceOf(TestIntegration);
84
- expect(TestIntegration.latestInstance.isHydrated).toBe(false);
85
- });
86
-
87
- it('calls initialize to register dynamic events', async () => {
88
- const dispatcher = createDispatcher();
89
- await dispatcher.integrationInstance.initialize();
90
- const result = await dispatcher.dispatchHttp({
91
- event: 'DYNAMIC_EVENT',
92
- req: {},
93
- res: {},
94
- next: jest.fn(),
95
- });
96
-
97
- expect(result).toEqual({ dynamic: true });
98
- expect(TestIntegration.latestInstance).toBeInstanceOf(TestIntegration);
99
- });
100
-
101
- it('throws when requesting an unknown event', async () => {
102
- const dispatcher = createDispatcher();
103
- await expect(
104
- dispatcher.dispatchHttp({
105
- event: 'UNKNOWN',
106
- req: {},
107
- res: {},
108
- next: jest.fn(),
109
- })
110
- ).rejects.toThrow('Event UNKNOWN not registered for test-integration');
111
- });
112
-
113
- it('does not hydrate automatically for handlers that require data', async () => {
114
- const dispatcher = createDispatcher();
115
- await expect(
116
- dispatcher.dispatchHttp({
117
- event: 'LOAD_DATA',
118
- req: {},
119
- res: {},
120
- next: jest.fn(),
121
- })
122
- ).rejects.toThrow('loadData requires hydration');
123
- });
124
- });
125
-
126
- describe('dispatchJob', () => {
127
- it('creates a stateless integration instance for job events', async () => {
128
- const payload = { foo: 'bar' };
129
- const dispatcher = createDispatcher();
130
- const result = await dispatcher.dispatchJob({
131
- event: 'TEST_EVENT',
132
- data: payload,
133
- context: {},
134
- });
135
-
136
- expect(result).toEqual({ received: payload });
137
- expect(TestIntegration.latestInstance).toBeInstanceOf(TestIntegration);
138
- expect(TestIntegration.latestInstance.isHydrated).toBe(false);
139
- });
140
- });
141
-
142
- describe('Webhook Events', () => {
143
- it('should dispatch WEBHOOK_RECEIVED without hydration', async () => {
144
- const integration = new TestIntegration();
145
- integration.events.WEBHOOK_RECEIVED = {
146
- handler: jest.fn().mockResolvedValue({ received: true })
147
- };
148
-
149
- const dispatcher = new IntegrationEventDispatcher(integration);
150
- const req = { body: { test: 'data' }, params: {} };
151
- const res = {};
152
-
153
- await dispatcher.dispatchHttp({
154
- event: 'WEBHOOK_RECEIVED',
155
- req,
156
- res,
157
- next: jest.fn()
158
- });
159
-
160
- expect(integration.events.WEBHOOK_RECEIVED.handler).toHaveBeenCalledWith({
161
- req,
162
- res,
163
- next: expect.any(Function)
164
- });
165
- });
166
-
167
- it('should dispatch ON_WEBHOOK with job context', async () => {
168
- const integration = new TestIntegration({ id: '123', userId: 'user1' });
169
- integration.events.ON_WEBHOOK = {
170
- handler: jest.fn().mockResolvedValue({ processed: true })
171
- };
172
-
173
- const dispatcher = new IntegrationEventDispatcher(integration);
174
- const data = { integrationId: '123', body: { event: 'test' } };
175
-
176
- await dispatcher.dispatchJob({
177
- event: 'ON_WEBHOOK',
178
- data,
179
- context: {}
180
- });
181
-
182
- expect(integration.events.ON_WEBHOOK.handler).toHaveBeenCalledWith({
183
- data,
184
- context: {}
185
- });
186
- expect(integration.isHydrated).toBe(true);
187
- });
188
-
189
- it('should use default WEBHOOK_RECEIVED handler if not overridden', async () => {
190
- const integration = new TestIntegration();
191
- const dispatcher = new IntegrationEventDispatcher(integration);
192
-
193
- const req = { body: { test: 'data' }, params: {}, headers: {}, query: {} };
194
- const res = { status: jest.fn().mockReturnThis(), json: jest.fn() };
195
-
196
- // Mock queueWebhook
197
- integration.queueWebhook = jest.fn().mockResolvedValue('message-id');
198
-
199
- const handler = dispatcher.findEventHandler(integration, 'WEBHOOK_RECEIVED');
200
- expect(handler).toBeDefined();
201
-
202
- await handler.call(integration, { req, res });
203
-
204
- expect(integration.queueWebhook).toHaveBeenCalled();
205
- expect(res.status).toHaveBeenCalledWith(200);
206
- expect(res.json).toHaveBeenCalledWith({ received: true });
207
- });
208
- });
209
- });
@@ -1,51 +0,0 @@
1
- /**
2
- * Adapter Layer Tests - Database Migration Router
3
- *
4
- * CRITICAL TEST: Verify handler loads without app definition
5
- *
6
- * Business logic is tested in:
7
- * - database/use-cases/trigger-database-migration-use-case.test.js (14 tests)
8
- * - database/use-cases/get-migration-status-use-case.test.js (11 tests)
9
- *
10
- * Following hexagonal architecture principles:
11
- * - Handlers are thin adapters (HTTP → Use Case → HTTP)
12
- * - Use cases contain all business logic (fully tested)
13
- * - Repositories are infrastructure adapters (tested separately)
14
- */
15
-
16
- process.env.ADMIN_API_KEY = 'test-admin-key';
17
- process.env.DB_MIGRATION_QUEUE_URL = 'https://sqs.test/queue';
18
-
19
- // Mock infrastructure dependencies to prevent app definition loading
20
- jest.mock('../../integrations/repositories/process-repository-postgres', () => ({
21
- ProcessRepositoryPostgres: jest.fn(() => ({
22
- create: jest.fn(),
23
- findById: jest.fn(),
24
- })),
25
- }));
26
-
27
- describe('Database Migration Router - Adapter Layer', () => {
28
- it('should load without requiring app definition (critical bug fix)', () => {
29
- // Before fix: createProcessRepository() → getDatabaseType() → loads app definition → requires integrations → CRASH
30
- // After fix: ProcessRepositoryPostgres instantiated directly → no app definition → SUCCESS
31
-
32
- expect(() => {
33
- require('./db-migration');
34
- }).not.toThrow();
35
- });
36
-
37
- it('should export handler and router', () => {
38
- const { handler, router } = require('./db-migration');
39
- expect(typeof handler).toBe('function');
40
- expect(typeof router).toBe('function');
41
- expect(router.stack).toBeDefined();
42
- });
43
-
44
- it('should hardcode dbType as postgresql (migrations are PostgreSQL-only)', () => {
45
- // Migration infrastructure is only created for PostgreSQL deployments
46
- // So we can safely hardcode dbType instead of requiring it from request
47
- const router = require('./db-migration').router;
48
- expect(router).toBeDefined();
49
- // Test will pass if handler doesn't crash when dbType is omitted from request
50
- });
51
- });