@friggframework/core 2.0.0--canary.548.c8ae0ca.0 → 2.0.0--canary.545.c40eca4.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.
- package/CHANGELOG.md +66 -67
- package/CLAUDE.md +148 -124
- package/README.md +165 -130
- package/admin-scripts/index.js +52 -0
- package/admin-scripts/repositories/admin-api-key-repository-documentdb.js +21 -0
- package/admin-scripts/repositories/admin-api-key-repository-factory.js +51 -0
- package/admin-scripts/repositories/admin-api-key-repository-interface.js +121 -0
- package/admin-scripts/repositories/admin-api-key-repository-mongo.js +155 -0
- package/admin-scripts/repositories/admin-api-key-repository-postgres.js +189 -0
- package/admin-scripts/repositories/admin-process-repository-documentdb.js +21 -0
- package/admin-scripts/repositories/admin-process-repository-factory.js +49 -0
- package/admin-scripts/repositories/admin-process-repository-interface.js +150 -0
- package/admin-scripts/repositories/admin-process-repository-mongo.js +213 -0
- package/admin-scripts/repositories/admin-process-repository-postgres.js +251 -0
- package/admin-scripts/repositories/script-execution-repository-documentdb.js +21 -0
- package/admin-scripts/repositories/script-execution-repository-factory.js +51 -0
- package/admin-scripts/repositories/script-execution-repository-interface.js +193 -0
- package/admin-scripts/repositories/script-execution-repository-mongo.js +278 -0
- package/admin-scripts/repositories/script-execution-repository-postgres.js +320 -0
- package/admin-scripts/repositories/script-schedule-repository-documentdb.js +21 -0
- package/admin-scripts/repositories/script-schedule-repository-factory.js +49 -0
- package/admin-scripts/repositories/script-schedule-repository-interface.js +108 -0
- package/admin-scripts/repositories/script-schedule-repository-mongo.js +179 -0
- package/admin-scripts/repositories/script-schedule-repository-postgres.js +210 -0
- package/application/commands/admin-script-commands.js +348 -0
- package/application/commands/integration-commands.js +12 -6
- package/application/index.js +5 -3
- package/assertions/get.js +17 -7
- package/associations/association.js +59 -57
- package/core/CLAUDE.md +222 -156
- package/core/Worker.js +33 -12
- package/credential/credential-router.js +262 -0
- package/credential/repositories/credential-repository-documentdb.js +71 -1
- package/credential/repositories/credential-repository-factory.js +4 -6
- package/credential/repositories/credential-repository-interface.js +8 -2
- package/credential/repositories/credential-repository-mongo.js +45 -4
- package/credential/repositories/credential-repository-postgres.js +44 -3
- package/credential/repositories/credential-repository.js +3 -1
- package/credential/use-cases/delete-credential-for-user.js +50 -0
- package/credential/use-cases/get-credential-for-user.js +21 -3
- package/credential/use-cases/list-credentials-for-user.js +31 -0
- package/credential/use-cases/reauthorize-credential.js +103 -0
- package/credential/use-cases/update-authentication-status.js +5 -2
- package/database/MONGODB_TRANSACTION_FIX.md +72 -52
- package/database/config.js +13 -59
- package/database/documentdb-encryption-service.js +29 -13
- package/database/documentdb-utils.js +21 -12
- package/database/encryption/README.md +53 -36
- package/database/encryption/encryption-schema-registry.js +29 -23
- package/database/encryption/field-encryption-service.js +15 -4
- package/database/encryption/logger.js +3 -2
- package/database/encryption/prisma-encryption-extension.js +5 -8
- package/database/prisma.js +22 -14
- package/database/repositories/health-check-repository-factory.js +7 -5
- package/database/repositories/health-check-repository-interface.js +15 -5
- package/database/repositories/health-check-repository-postgres.js +1 -1
- package/database/use-cases/check-database-health-use-case.js +3 -2
- package/database/use-cases/check-database-state-use-case.js +8 -7
- package/database/use-cases/get-database-state-via-worker-use-case.js +15 -12
- package/database/use-cases/get-migration-status-use-case.js +4 -2
- package/database/use-cases/run-database-migration-use-case.js +41 -9
- package/database/use-cases/test-encryption-use-case.js +4 -5
- package/database/use-cases/trigger-database-migration-use-case.js +9 -8
- package/database/utils/mongodb-collection-utils.js +11 -3
- package/database/utils/mongodb-schema-init.js +10 -4
- package/database/utils/prisma-runner.js +144 -74
- package/database/utils/prisma-schema-parser.js +2 -2
- package/docs/PROCESS_MANAGEMENT_QUEUE_SPEC.md +135 -80
- package/encrypt/Cryptor.js +54 -49
- package/encrypt/aes-encryption-key-provider.js +82 -0
- package/encrypt/encryption-key-provider-interface.js +50 -0
- package/errors/fetch-error.js +1 -1
- package/generated/prisma-mongodb/edge.js +59 -4
- package/generated/prisma-mongodb/index-browser.js +49 -1
- package/generated/prisma-mongodb/index.d.ts +4023 -61
- package/generated/prisma-mongodb/index.js +59 -4
- package/generated/prisma-mongodb/package.json +1 -1
- package/generated/prisma-mongodb/schema.prisma +87 -0
- package/generated/prisma-mongodb/wasm.js +59 -4
- package/generated/prisma-postgresql/edge.js +58 -4
- package/generated/prisma-postgresql/index-browser.js +48 -1
- package/generated/prisma-postgresql/index.d.ts +4738 -54
- package/generated/prisma-postgresql/index.js +58 -4
- package/generated/prisma-postgresql/package.json +1 -1
- package/generated/prisma-postgresql/schema.prisma +85 -0
- package/generated/prisma-postgresql/wasm.js +58 -4
- package/handlers/WEBHOOKS.md +104 -81
- package/handlers/app-definition-loader.js +53 -10
- package/handlers/app-handler-helpers.js +14 -3
- package/handlers/backend-utils.js +0 -1
- package/handlers/database-migration-handler.js +64 -45
- package/handlers/middleware/admin-auth.js +53 -0
- package/handlers/routers/HEALTHCHECK.md +170 -135
- package/handlers/routers/admin.js +474 -0
- package/handlers/routers/auth.js +51 -9
- package/handlers/routers/db-migration.handler.js +2 -3
- package/handlers/routers/db-migration.js +102 -66
- package/handlers/routers/docs.js +180 -0
- package/handlers/routers/health.js +84 -283
- package/handlers/routers/integration-defined-routers.js +44 -33
- package/handlers/routers/integration-webhook-routers.js +73 -52
- package/handlers/routers/middleware/loadUser.js +39 -0
- package/handlers/routers/middleware/requireAdmin.js +43 -0
- package/handlers/routers/middleware/requireLoggedInUser.js +19 -0
- package/handlers/routers/user.js +30 -14
- package/handlers/routers/websocket.js +18 -4
- package/handlers/use-cases/check-integrations-health-use-case.js +13 -6
- package/handlers/workers/db-migration.js +74 -35
- package/handlers/workers/integration-defined-workers.js +31 -20
- package/index.js +50 -16
- package/infrastructure/scheduler/index.js +15 -11
- package/infrastructure/scheduler/netlify-scheduler-adapter.js +185 -0
- package/infrastructure/scheduler/scheduler-service-factory.js +38 -31
- package/integrations/WEBHOOK-QUICKSTART.md +21 -14
- package/integrations/index.js +4 -0
- package/integrations/integration-base.js +9 -6
- package/integrations/integration-router.js +1828 -157
- package/integrations/options.js +47 -20
- package/integrations/repositories/integration-mapping-repository-factory.js +4 -8
- package/integrations/repositories/integration-repository-documentdb.js +53 -24
- package/integrations/repositories/integration-repository-factory.js +6 -6
- package/integrations/repositories/integration-repository-interface.js +27 -9
- package/integrations/repositories/integration-repository-postgres.js +3 -3
- package/integrations/repositories/process-repository-factory.js +4 -7
- package/integrations/repositories/process-repository-interface.js +9 -5
- package/integrations/repositories/process-repository-mongo.js +7 -3
- package/integrations/repositories/process-repository-postgres.js +2 -2
- package/integrations/tests/doubles/config-capturing-integration.js +9 -8
- package/integrations/tests/doubles/dummy-integration-class.js +81 -8
- package/integrations/tests/doubles/test-integration-repository.js +51 -11
- package/integrations/use-cases/create-integration.js +36 -32
- package/integrations/use-cases/create-process.js +20 -9
- package/integrations/use-cases/delete-integration-for-user.js +5 -4
- package/integrations/use-cases/execute-proxy-request.js +564 -0
- package/integrations/use-cases/get-integration-for-user.js +25 -10
- package/integrations/use-cases/get-integration-instance-by-definition.js +13 -7
- package/integrations/use-cases/get-integrations-for-user.js +4 -1
- package/integrations/use-cases/get-possible-integrations.js +1 -1
- package/integrations/use-cases/get-process.js +5 -6
- package/integrations/use-cases/index.js +3 -1
- package/integrations/use-cases/load-integration-context.js +1 -5
- package/integrations/use-cases/update-process-state.js +10 -8
- package/integrations/utils/map-integration-dto.js +9 -3
- package/jest-setup.js +1 -1
- package/jest-teardown.js +1 -1
- package/lambda/TimeoutCatcher.js +32 -30
- package/lambda/index.js +1 -1
- package/logs/index.js +3 -3
- package/modules/domain/entities/AuthorizationSession.js +131 -0
- package/modules/domain/entities/index.js +10 -0
- package/modules/module.js +4 -9
- package/modules/repositories/authorization-session-repository-factory.js +53 -0
- package/modules/repositories/authorization-session-repository-interface.js +75 -0
- package/modules/repositories/authorization-session-repository-mongo.js +169 -0
- package/modules/repositories/authorization-session-repository-postgres.js +170 -0
- package/modules/repositories/module-repository-documentdb.js +89 -41
- package/modules/repositories/module-repository-factory.js +4 -6
- package/modules/repositories/module-repository-interface.js +13 -0
- package/modules/repositories/module-repository-mongo.js +40 -5
- package/modules/repositories/module-repository-postgres.js +42 -5
- package/modules/repositories/module-repository.js +28 -0
- package/modules/requester/api-key.js +0 -2
- package/modules/requester/basic.js +0 -1
- package/modules/requester/oauth-2.js +3 -14
- package/modules/test/mock-api/definition.js +15 -10
- package/modules/test/mock-api/mocks/hubspot.js +36 -36
- package/modules/tests/doubles/test-module-factory.js +10 -4
- package/modules/tests/doubles/test-module-repository.js +1 -1
- package/modules/use-cases/delete-module-entity.js +23 -0
- package/modules/use-cases/get-authorization-requirements.js +110 -0
- package/modules/use-cases/get-entities-for-user.js +1 -1
- package/modules/use-cases/get-entity-options-by-id.js +8 -6
- package/modules/use-cases/get-module-entity-by-id.js +16 -0
- package/modules/use-cases/get-module.js +12 -9
- package/modules/use-cases/process-authorization-callback.js +12 -6
- package/modules/use-cases/process-authorization-step.js +160 -0
- package/modules/use-cases/refresh-entity-options.js +8 -6
- package/modules/use-cases/start-authorization-session.js +86 -0
- package/modules/use-cases/test-module-auth.js +8 -6
- package/modules/use-cases/update-module-entity.js +27 -0
- package/modules/utils/map-module-dto.js +2 -2
- package/openapi/openapi-spec-generator.js +370 -0
- package/openapi/openapi-v1.yaml +1360 -0
- package/openapi/openapi-v2.yaml +1535 -0
- package/package.json +7 -9
- package/prisma-mongodb/schema.prisma +87 -0
- package/prisma-postgresql/migrations/20260222000000_add_admin_process_and_script_schedule/migration.sql +55 -0
- package/prisma-postgresql/schema.prisma +85 -0
- package/providers/index.js +13 -0
- package/providers/resolve-provider.js +93 -0
- package/queues/index.js +19 -0
- package/queues/providers/index.js +7 -0
- package/queues/providers/netlify-background-provider.js +76 -0
- package/queues/providers/qstash-queue-provider.js +122 -0
- package/queues/queue-client-interface.js +55 -0
- package/queues/queue-provider-factory.js +93 -0
- package/queues/queue-provider.js +46 -0
- package/queues/queuer-util.js +33 -25
- package/syncs/repositories/sync-repository-documentdb.js +39 -19
- package/syncs/repositories/sync-repository-factory.js +4 -4
- package/syncs/repositories/sync-repository-interface.js +6 -2
- package/syncs/repositories/sync-repository-postgres.js +19 -13
- package/syncs/sync.js +104 -100
- package/token/repositories/token-repository-factory.js +4 -6
- package/types/assertions/index.d.ts +72 -72
- package/types/core/index.d.ts +98 -53
- package/types/errors/index.d.ts +61 -54
- package/types/eslint-config/index.d.ts +40 -40
- package/types/lambda/index.d.ts +26 -26
- package/types/logs/index.d.ts +4 -4
- package/types/prettier-config/index.d.ts +5 -5
- package/types/test-environment/index.d.ts +14 -14
- package/types/tsconfig.json +95 -93
- package/user/repositories/user-repository-factory.js +4 -4
- package/user/tests/doubles/test-user-repository.js +5 -2
- package/user/use-cases/authenticate-user.js +2 -4
- package/user/use-cases/authenticate-with-shared-secret.js +1 -1
- package/user/use-cases/create-individual-user.js +8 -7
- package/user/use-cases/create-organization-user.js +1 -1
- package/user/use-cases/create-token-for-user-id.js +1 -1
- package/user/use-cases/delete-user.js +47 -0
- package/user/use-cases/get-user-from-adopter-jwt.js +0 -2
- package/user/use-cases/get-user-from-bearer-token.js +7 -3
- package/user/use-cases/get-user-from-x-frigg-headers.js +14 -11
- package/user/use-cases/login-user.js +8 -8
- package/user/user.js +18 -4
- package/utils/backend-path.js +2 -2
- package/utils/index.js +4 -1
- package/websocket/repositories/websocket-connection-repository-documentdb.js +46 -21
- package/websocket/repositories/websocket-connection-repository-factory.js +4 -8
- package/websocket/repositories/websocket-connection-repository-mongo.js +26 -16
- package/websocket/repositories/websocket-connection-repository-postgres.js +26 -15
- package/websocket/repositories/websocket-connection-repository.js +26 -20
- package/websocket/websocket-message-sender-interface.js +38 -0
- package/database/adapters/lambda-invoker.js +0 -97
- package/database/repositories/migration-status-repository-s3.js +0 -137
- package/infrastructure/scheduler/eventbridge-scheduler-adapter.js +0 -184
|
@@ -58,7 +58,9 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
58
58
|
return new Map();
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
const validIds = credentialIds.filter(
|
|
61
|
+
const validIds = credentialIds.filter(
|
|
62
|
+
(id) => id !== null && id !== undefined
|
|
63
|
+
);
|
|
62
64
|
|
|
63
65
|
if (validIds.length === 0) {
|
|
64
66
|
return new Map();
|
|
@@ -118,7 +120,9 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
118
120
|
where: { userId },
|
|
119
121
|
});
|
|
120
122
|
|
|
121
|
-
const credentialIds = entities
|
|
123
|
+
const credentialIds = entities
|
|
124
|
+
.map((e) => e.credentialId)
|
|
125
|
+
.filter(Boolean);
|
|
122
126
|
const credentialMap = await this._fetchCredentialsBulk(credentialIds);
|
|
123
127
|
|
|
124
128
|
return entities.map((e) => ({
|
|
@@ -144,7 +148,9 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
144
148
|
where: { id: { in: entitiesIds } },
|
|
145
149
|
});
|
|
146
150
|
|
|
147
|
-
const credentialIds = entities
|
|
151
|
+
const credentialIds = entities
|
|
152
|
+
.map((e) => e.credentialId)
|
|
153
|
+
.filter(Boolean);
|
|
148
154
|
const credentialMap = await this._fetchCredentialsBulk(credentialIds);
|
|
149
155
|
|
|
150
156
|
return entities.map((e) => ({
|
|
@@ -174,7 +180,9 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
174
180
|
},
|
|
175
181
|
});
|
|
176
182
|
|
|
177
|
-
const credentialIds = entities
|
|
183
|
+
const credentialIds = entities
|
|
184
|
+
.map((e) => e.credentialId)
|
|
185
|
+
.filter(Boolean);
|
|
178
186
|
const credentialMap = await this._fetchCredentialsBulk(credentialIds);
|
|
179
187
|
|
|
180
188
|
return entities.map((e) => ({
|
|
@@ -234,6 +242,31 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
234
242
|
};
|
|
235
243
|
}
|
|
236
244
|
|
|
245
|
+
/**
|
|
246
|
+
* Find entities matching filter criteria
|
|
247
|
+
* @param {Object} filter - Filter criteria (e.g., { isGlobal: true, moduleName: 'api-name' })
|
|
248
|
+
* @returns {Promise<Array>} Array of entity objects with string IDs
|
|
249
|
+
*/
|
|
250
|
+
async findEntitiesBy(filter) {
|
|
251
|
+
const where = this._convertFilterToWhere(filter);
|
|
252
|
+
const entities = await this.prisma.entity.findMany({
|
|
253
|
+
where,
|
|
254
|
+
include: { credential: true },
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
return entities.map((e) => ({
|
|
258
|
+
id: e.id,
|
|
259
|
+
accountId: e.accountId,
|
|
260
|
+
credential: e.credential,
|
|
261
|
+
userId: e.userId,
|
|
262
|
+
name: e.name,
|
|
263
|
+
externalId: e.externalId,
|
|
264
|
+
type: e.subType,
|
|
265
|
+
moduleName: e.moduleName,
|
|
266
|
+
isGlobal: e.isGlobal,
|
|
267
|
+
}));
|
|
268
|
+
}
|
|
269
|
+
|
|
237
270
|
/**
|
|
238
271
|
* Create a new entity
|
|
239
272
|
* Replaces: Entity.create(entityData)
|
|
@@ -399,7 +432,9 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
399
432
|
if (filter.credentialId) where.credentialId = filter.credentialId;
|
|
400
433
|
if (filter.name) where.name = filter.name;
|
|
401
434
|
if (filter.moduleName) where.moduleName = filter.moduleName;
|
|
402
|
-
if (filter.externalId)
|
|
435
|
+
if (filter.externalId)
|
|
436
|
+
where.externalId = this._toString(filter.externalId);
|
|
437
|
+
if (filter.isGlobal !== undefined) where.isGlobal = filter.isGlobal;
|
|
403
438
|
|
|
404
439
|
return where;
|
|
405
440
|
}
|
|
@@ -87,7 +87,9 @@ class ModuleRepositoryPostgres extends ModuleRepositoryInterface {
|
|
|
87
87
|
return new Map();
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
const validIds = credentialIds.filter(
|
|
90
|
+
const validIds = credentialIds.filter(
|
|
91
|
+
(id) => id !== null && id !== undefined
|
|
92
|
+
);
|
|
91
93
|
|
|
92
94
|
if (validIds.length === 0) {
|
|
93
95
|
return new Map();
|
|
@@ -154,7 +156,9 @@ class ModuleRepositoryPostgres extends ModuleRepositoryInterface {
|
|
|
154
156
|
where: { userId: intUserId },
|
|
155
157
|
});
|
|
156
158
|
|
|
157
|
-
const credentialIds = entities
|
|
159
|
+
const credentialIds = entities
|
|
160
|
+
.map((e) => e.credentialId)
|
|
161
|
+
.filter(Boolean);
|
|
158
162
|
const credentialMap = await this._fetchCredentialsBulk(credentialIds);
|
|
159
163
|
|
|
160
164
|
return entities.map((e) => ({
|
|
@@ -182,7 +186,9 @@ class ModuleRepositoryPostgres extends ModuleRepositoryInterface {
|
|
|
182
186
|
where: { id: { in: intIds } },
|
|
183
187
|
});
|
|
184
188
|
|
|
185
|
-
const credentialIds = entities
|
|
189
|
+
const credentialIds = entities
|
|
190
|
+
.map((e) => e.credentialId)
|
|
191
|
+
.filter(Boolean);
|
|
186
192
|
const credentialMap = await this._fetchCredentialsBulk(credentialIds);
|
|
187
193
|
|
|
188
194
|
return entities.map((e) => ({
|
|
@@ -214,7 +220,9 @@ class ModuleRepositoryPostgres extends ModuleRepositoryInterface {
|
|
|
214
220
|
},
|
|
215
221
|
});
|
|
216
222
|
|
|
217
|
-
const credentialIds = entities
|
|
223
|
+
const credentialIds = entities
|
|
224
|
+
.map((e) => e.credentialId)
|
|
225
|
+
.filter(Boolean);
|
|
218
226
|
const credentialMap = await this._fetchCredentialsBulk(credentialIds);
|
|
219
227
|
|
|
220
228
|
return entities.map((e) => ({
|
|
@@ -275,6 +283,33 @@ class ModuleRepositoryPostgres extends ModuleRepositoryInterface {
|
|
|
275
283
|
};
|
|
276
284
|
}
|
|
277
285
|
|
|
286
|
+
/**
|
|
287
|
+
* Find entities matching filter criteria
|
|
288
|
+
* Replaces: Entity.find(filter).populate('credential')
|
|
289
|
+
*
|
|
290
|
+
* @param {Object} filter - Filter criteria (e.g., { isGlobal: true, type: 'someType', status: 'connected' })
|
|
291
|
+
* @returns {Promise<Array>} Array of entity objects with string IDs
|
|
292
|
+
*/
|
|
293
|
+
async findEntitiesBy(filter) {
|
|
294
|
+
const where = this._convertFilterToWhere(filter);
|
|
295
|
+
const entities = await this.prisma.entity.findMany({
|
|
296
|
+
where,
|
|
297
|
+
include: { credential: true },
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
return entities.map((e) => ({
|
|
301
|
+
id: e.id.toString(),
|
|
302
|
+
accountId: e.accountId,
|
|
303
|
+
credential: this._convertCredentialIds(e.credential),
|
|
304
|
+
userId: e.userId?.toString(),
|
|
305
|
+
name: e.name,
|
|
306
|
+
externalId: e.externalId,
|
|
307
|
+
type: e.subType,
|
|
308
|
+
moduleName: e.moduleName,
|
|
309
|
+
isGlobal: e.isGlobal,
|
|
310
|
+
}));
|
|
311
|
+
}
|
|
312
|
+
|
|
278
313
|
/**
|
|
279
314
|
* Create a new entity
|
|
280
315
|
* Replaces: Entity.create(entityData)
|
|
@@ -444,7 +479,9 @@ class ModuleRepositoryPostgres extends ModuleRepositoryInterface {
|
|
|
444
479
|
where.credentialId = this._convertId(filter.credentialId);
|
|
445
480
|
if (filter.name) where.name = filter.name;
|
|
446
481
|
if (filter.moduleName) where.moduleName = filter.moduleName;
|
|
447
|
-
if (filter.externalId)
|
|
482
|
+
if (filter.externalId)
|
|
483
|
+
where.externalId = this._toString(filter.externalId);
|
|
484
|
+
if (filter.isGlobal !== undefined) where.isGlobal = filter.isGlobal;
|
|
448
485
|
|
|
449
486
|
return where;
|
|
450
487
|
}
|
|
@@ -172,6 +172,33 @@ class ModuleRepository extends ModuleRepositoryInterface {
|
|
|
172
172
|
};
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
+
/**
|
|
176
|
+
* Find entities matching filter criteria
|
|
177
|
+
* Replaces: Entity.find(filter).populate('credential')
|
|
178
|
+
*
|
|
179
|
+
* @param {Object} filter - Filter criteria
|
|
180
|
+
* @returns {Promise<Array>} Array of entity objects
|
|
181
|
+
*/
|
|
182
|
+
async findEntitiesBy(filter) {
|
|
183
|
+
const where = this._convertFilterToWhere(filter);
|
|
184
|
+
const entities = await this.prisma.entity.findMany({
|
|
185
|
+
where,
|
|
186
|
+
include: { credential: true },
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
return entities.map((e) => ({
|
|
190
|
+
id: e.id,
|
|
191
|
+
accountId: e.accountId,
|
|
192
|
+
credential: e.credential,
|
|
193
|
+
userId: e.userId,
|
|
194
|
+
name: e.name,
|
|
195
|
+
externalId: e.externalId,
|
|
196
|
+
type: e.subType,
|
|
197
|
+
moduleName: e.moduleName,
|
|
198
|
+
isGlobal: e.isGlobal,
|
|
199
|
+
}));
|
|
200
|
+
}
|
|
201
|
+
|
|
175
202
|
/**
|
|
176
203
|
* Create a new entity
|
|
177
204
|
* Replaces: Entity.create(entityData)
|
|
@@ -337,6 +364,7 @@ class ModuleRepository extends ModuleRepositoryInterface {
|
|
|
337
364
|
if (filter.name) where.name = filter.name;
|
|
338
365
|
if (filter.moduleName) where.moduleName = filter.moduleName;
|
|
339
366
|
if (filter.externalId) where.externalId = filter.externalId;
|
|
367
|
+
if (filter.isGlobal !== undefined) where.isGlobal = filter.isGlobal;
|
|
340
368
|
|
|
341
369
|
return where;
|
|
342
370
|
}
|
|
@@ -2,9 +2,7 @@ const { Requester } = require('./requester');
|
|
|
2
2
|
const { get } = require('../../assertions');
|
|
3
3
|
const { ModuleConstants } = require('../ModuleConstants');
|
|
4
4
|
|
|
5
|
-
|
|
6
5
|
class ApiKeyRequester extends Requester {
|
|
7
|
-
|
|
8
6
|
static requesterType = ModuleConstants.authType.apiKey;
|
|
9
7
|
|
|
10
8
|
constructor(params) {
|
|
@@ -117,16 +117,6 @@ class OAuth2Requester extends Requester {
|
|
|
117
117
|
const newRefreshToken = get(params, 'refresh_token', null);
|
|
118
118
|
if (newRefreshToken !== null) {
|
|
119
119
|
this.refresh_token = newRefreshToken;
|
|
120
|
-
} else {
|
|
121
|
-
if (this.refresh_token) {
|
|
122
|
-
console.log(
|
|
123
|
-
'[Frigg] No refresh_token in response, preserving existing'
|
|
124
|
-
);
|
|
125
|
-
} else {
|
|
126
|
-
console.log(
|
|
127
|
-
'[Frigg] Current refresh_token is null and no new refresh_token in response'
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
120
|
}
|
|
131
121
|
const accessExpiresIn = get(params, 'expires_in', null);
|
|
132
122
|
const refreshExpiresIn = get(
|
|
@@ -248,7 +238,6 @@ class OAuth2Requester extends Requester {
|
|
|
248
238
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
249
239
|
},
|
|
250
240
|
};
|
|
251
|
-
console.log('[Frigg] Refreshing access token with options');
|
|
252
241
|
const response = await this._post(options, false);
|
|
253
242
|
await this.setTokens(response);
|
|
254
243
|
return response;
|
|
@@ -296,7 +285,7 @@ class OAuth2Requester extends Requester {
|
|
|
296
285
|
*/
|
|
297
286
|
async refreshAuth() {
|
|
298
287
|
try {
|
|
299
|
-
console.log('[
|
|
288
|
+
console.log('[OAuth2Requester.refreshAuth] Starting token refresh', {
|
|
300
289
|
grant_type: this.grant_type,
|
|
301
290
|
has_refresh_token: !!this.refresh_token,
|
|
302
291
|
has_client_id: !!this.client_id,
|
|
@@ -312,10 +301,10 @@ class OAuth2Requester extends Requester {
|
|
|
312
301
|
} else {
|
|
313
302
|
await this.getTokenFromClientCredentials();
|
|
314
303
|
}
|
|
315
|
-
console.log('[
|
|
304
|
+
console.log('[OAuth2Requester.refreshAuth] Token refresh succeeded');
|
|
316
305
|
return true;
|
|
317
306
|
} catch (error) {
|
|
318
|
-
console.error('[
|
|
307
|
+
console.error('[OAuth2Requester.refreshAuth] Token refresh failed', {
|
|
319
308
|
error_message: error?.message,
|
|
320
309
|
error_name: error?.name,
|
|
321
310
|
response_status: error?.response?.status,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require('dotenv').config();
|
|
2
2
|
const { Api } = require('./api');
|
|
3
3
|
const { get } = require('../../../assertions');
|
|
4
|
-
const config = { name: 'anapi' }
|
|
4
|
+
const config = { name: 'anapi' };
|
|
5
5
|
|
|
6
6
|
const Definition = {
|
|
7
7
|
API: Api,
|
|
@@ -9,7 +9,9 @@ const Definition = {
|
|
|
9
9
|
url: 'http://localhost:3000/redirect/anapi',
|
|
10
10
|
type: 'oauth2',
|
|
11
11
|
}),
|
|
12
|
-
getName: function () {
|
|
12
|
+
getName: function () {
|
|
13
|
+
return config.name;
|
|
14
|
+
},
|
|
13
15
|
moduleName: config.name,
|
|
14
16
|
modelName: 'AnApi',
|
|
15
17
|
requiredAuthMethods: {
|
|
@@ -17,28 +19,31 @@ const Definition = {
|
|
|
17
19
|
const code = get(params.data, 'code');
|
|
18
20
|
return api.getTokenFromCode(code);
|
|
19
21
|
},
|
|
20
|
-
getEntityDetails: async function (
|
|
22
|
+
getEntityDetails: async function (
|
|
23
|
+
api,
|
|
24
|
+
callbackParams,
|
|
25
|
+
tokenResponse,
|
|
26
|
+
userId
|
|
27
|
+
) {
|
|
21
28
|
const userDetails = await api.getUserDetails();
|
|
22
29
|
return {
|
|
23
30
|
identifiers: { externalId: userDetails.portalId, userId },
|
|
24
31
|
details: { name: userDetails.hub_domain },
|
|
25
|
-
}
|
|
32
|
+
};
|
|
26
33
|
},
|
|
27
34
|
apiPropertiesToPersist: {
|
|
28
|
-
credential: [
|
|
29
|
-
'access_token', 'refresh_token'
|
|
30
|
-
],
|
|
35
|
+
credential: ['access_token', 'refresh_token'],
|
|
31
36
|
entity: [],
|
|
32
37
|
},
|
|
33
38
|
getCredentialDetails: async function (api, userId) {
|
|
34
39
|
const userDetails = await api.getUserDetails();
|
|
35
40
|
return {
|
|
36
41
|
identifiers: { externalId: userDetails.portalId, userId },
|
|
37
|
-
details: {}
|
|
42
|
+
details: {},
|
|
38
43
|
};
|
|
39
44
|
},
|
|
40
45
|
testAuthRequest: async function (api) {
|
|
41
|
-
return api.getUserDetails()
|
|
46
|
+
return api.getUserDetails();
|
|
42
47
|
},
|
|
43
48
|
},
|
|
44
49
|
env: {
|
|
@@ -46,7 +51,7 @@ const Definition = {
|
|
|
46
51
|
client_secret: 'test',
|
|
47
52
|
scope: 'test',
|
|
48
53
|
redirect_uri: `http://localhost:3000/redirect/anapi`,
|
|
49
|
-
}
|
|
54
|
+
},
|
|
50
55
|
};
|
|
51
56
|
|
|
52
57
|
module.exports = { Definition };
|
|
@@ -1,43 +1,43 @@
|
|
|
1
1
|
const authorizeResponse = {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
}
|
|
2
|
+
base: '/redirect/hubspot',
|
|
3
|
+
data: {
|
|
4
|
+
code: 'test-code',
|
|
5
|
+
state: 'null',
|
|
6
|
+
},
|
|
7
|
+
};
|
|
8
8
|
|
|
9
9
|
const tokenResponse = {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
10
|
+
token_type: 'bearer',
|
|
11
|
+
refresh_token: 'test-refresh-token',
|
|
12
|
+
access_token: 'test-access-token',
|
|
13
|
+
expires_in: 1800,
|
|
14
|
+
};
|
|
15
15
|
|
|
16
16
|
const userDetailsResponse = {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
17
|
+
portalId: 111111111,
|
|
18
|
+
timeZone: 'US/Eastern',
|
|
19
|
+
accountType: 'DEVELOPER_TEST',
|
|
20
|
+
currency: 'USD',
|
|
21
|
+
utcOffset: '-05:00',
|
|
22
|
+
utcOffsetMilliseconds: -18000000,
|
|
23
|
+
token: 'test-token',
|
|
24
|
+
user: 'projectteam@lefthook.co',
|
|
25
|
+
hub_domain: 'Testing Object Things-dev-44613847.com',
|
|
26
|
+
scopes: [
|
|
27
|
+
'content',
|
|
28
|
+
'oauth',
|
|
29
|
+
'crm.objects.contacts.read',
|
|
30
|
+
'crm.objects.contacts.write',
|
|
31
|
+
'crm.objects.companies.write',
|
|
32
|
+
'crm.objects.companies.read',
|
|
33
|
+
'crm.objects.deals.read',
|
|
34
|
+
'crm.schemas.deals.read',
|
|
35
35
|
],
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
36
|
+
hub_id: 111111111,
|
|
37
|
+
app_id: 22222222,
|
|
38
|
+
expires_in: 1704,
|
|
39
|
+
user_id: 33333333,
|
|
40
|
+
token_type: 'access',
|
|
41
|
+
};
|
|
42
42
|
|
|
43
|
-
module.exports = { authorizeResponse, tokenResponse, userDetailsResponse }
|
|
43
|
+
module.exports = { authorizeResponse, tokenResponse, userDetailsResponse };
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
class TestModuleFactory {
|
|
2
|
-
constructor() {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.moduleRepository = {
|
|
4
|
+
findEntity: jest.fn().mockResolvedValue(null),
|
|
5
|
+
findEntitiesBy: jest.fn().mockResolvedValue([]),
|
|
6
|
+
};
|
|
7
|
+
}
|
|
3
8
|
|
|
4
9
|
async getModuleInstance(entityId, userId) {
|
|
5
|
-
// return minimal stub module with getName and api property
|
|
6
10
|
return {
|
|
7
|
-
getName() {
|
|
11
|
+
getName() {
|
|
12
|
+
return 'stubModule';
|
|
13
|
+
},
|
|
8
14
|
api: {},
|
|
9
15
|
entityId,
|
|
10
16
|
userId,
|
|
@@ -13,4 +19,4 @@ class TestModuleFactory {
|
|
|
13
19
|
}
|
|
14
20
|
}
|
|
15
21
|
|
|
16
|
-
module.exports = { TestModuleFactory };
|
|
22
|
+
module.exports = { TestModuleFactory };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeleteModuleEntity Use Case
|
|
3
|
+
* Deletes a module entity by its ID
|
|
4
|
+
*/
|
|
5
|
+
class DeleteModuleEntity {
|
|
6
|
+
constructor({ moduleRepository }) {
|
|
7
|
+
this.moduleRepository = moduleRepository;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async execute(entityId) {
|
|
11
|
+
const entity = await this.moduleRepository.findEntityById(entityId);
|
|
12
|
+
|
|
13
|
+
if (!entity) {
|
|
14
|
+
throw new Error(`Entity not found: ${entityId}`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
await this.moduleRepository.deleteEntity(entityId);
|
|
18
|
+
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
module.exports = { DeleteModuleEntity };
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get Authorization Requirements Use Case
|
|
3
|
+
* Business logic for retrieving authorization requirements for a specific step
|
|
4
|
+
*
|
|
5
|
+
* Responsibilities:
|
|
6
|
+
* - Find module definition for entity type
|
|
7
|
+
* - Determine step count (single vs multi-step)
|
|
8
|
+
* - Retrieve step-specific requirements (jsonSchema, uiSchema, etc.)
|
|
9
|
+
* - Return structured requirements for frontend rendering
|
|
10
|
+
*
|
|
11
|
+
* Supports both single-step and multi-step modules:
|
|
12
|
+
* - Single-step: Uses getAuthorizationRequirements() (legacy)
|
|
13
|
+
* - Multi-step: Uses getAuthRequirementsForStep(step) (new)
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```javascript
|
|
17
|
+
* const useCase = new GetAuthorizationRequirementsUseCase({
|
|
18
|
+
* moduleDefinitions: [{ moduleName: 'nagaris', definition: NagarisDefinition }]
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* // Get requirements for step 1
|
|
22
|
+
* const reqs = await useCase.execute('nagaris', 1);
|
|
23
|
+
* // Returns: { type: 'email', data: { jsonSchema, uiSchema }, step: 1, totalSteps: 2, isMultiStep: true }
|
|
24
|
+
*
|
|
25
|
+
* // Get requirements for step 2
|
|
26
|
+
* const reqs = await useCase.execute('nagaris', 2);
|
|
27
|
+
* // Returns: { type: 'otp', data: { jsonSchema, uiSchema }, step: 2, totalSteps: 2, isMultiStep: true }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
class GetAuthorizationRequirementsUseCase {
|
|
31
|
+
/**
|
|
32
|
+
* @param {Object} params - Dependencies
|
|
33
|
+
* @param {Array<Object>} params.moduleDefinitions - Array of module definitions with structure: { moduleName, definition }
|
|
34
|
+
*/
|
|
35
|
+
constructor({ moduleDefinitions }) {
|
|
36
|
+
if (!moduleDefinitions || !Array.isArray(moduleDefinitions)) {
|
|
37
|
+
throw new Error('moduleDefinitions array is required');
|
|
38
|
+
}
|
|
39
|
+
this.moduleDefinitions = moduleDefinitions;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Get authorization requirements for a specific step
|
|
44
|
+
*
|
|
45
|
+
* @param {string} entityType - Entity type (module name)
|
|
46
|
+
* @param {number} [step=1] - Step number (1-indexed)
|
|
47
|
+
* @returns {Promise<Object>} Requirements object with schema and metadata
|
|
48
|
+
* @throws {Error} If module not found or step invalid
|
|
49
|
+
*/
|
|
50
|
+
async execute(entityType, step = 1) {
|
|
51
|
+
// Validate inputs
|
|
52
|
+
if (!entityType) {
|
|
53
|
+
throw new Error('entityType is required');
|
|
54
|
+
}
|
|
55
|
+
if (!step || step < 1) {
|
|
56
|
+
throw new Error('step must be >= 1');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Find module definition
|
|
60
|
+
const moduleDefinition = this.moduleDefinitions.find(
|
|
61
|
+
(def) => def.moduleName === entityType
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
if (!moduleDefinition) {
|
|
65
|
+
throw new Error(`Module definition not found: ${entityType}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const ModuleDefinition = moduleDefinition.definition;
|
|
69
|
+
|
|
70
|
+
// Determine step count (multi-step vs single-step)
|
|
71
|
+
const stepCount = ModuleDefinition.getAuthStepCount
|
|
72
|
+
? ModuleDefinition.getAuthStepCount()
|
|
73
|
+
: 1;
|
|
74
|
+
|
|
75
|
+
// Validate requested step doesn't exceed max steps
|
|
76
|
+
if (step > stepCount) {
|
|
77
|
+
throw new Error(
|
|
78
|
+
`Step ${step} exceeds maximum steps (${stepCount}) for ${entityType}`
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Get requirements for this specific step
|
|
83
|
+
let requirements;
|
|
84
|
+
|
|
85
|
+
if (ModuleDefinition.getAuthRequirementsForStep) {
|
|
86
|
+
// Multi-step module - use step-specific method
|
|
87
|
+
requirements = await ModuleDefinition.getAuthRequirementsForStep(
|
|
88
|
+
step
|
|
89
|
+
);
|
|
90
|
+
} else if (step === 1) {
|
|
91
|
+
// Single-step module (legacy) - use standard method
|
|
92
|
+
requirements =
|
|
93
|
+
await ModuleDefinition.getAuthorizationRequirements();
|
|
94
|
+
} else {
|
|
95
|
+
throw new Error(
|
|
96
|
+
`Module ${entityType} does not support step ${step}`
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Return enriched requirements with metadata
|
|
101
|
+
return {
|
|
102
|
+
...requirements,
|
|
103
|
+
step,
|
|
104
|
+
totalSteps: stepCount,
|
|
105
|
+
isMultiStep: stepCount > 1,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
module.exports = { GetAuthorizationRequirementsUseCase };
|
|
@@ -20,9 +20,10 @@ class GetEntityOptionsById {
|
|
|
20
20
|
*/
|
|
21
21
|
async execute(entityId, userIdOrUser) {
|
|
22
22
|
// Support both userId (backward compatible) and User object (new pattern)
|
|
23
|
-
const userId =
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
const userId =
|
|
24
|
+
typeof userIdOrUser === 'object' && userIdOrUser?.getId
|
|
25
|
+
? userIdOrUser.getId()
|
|
26
|
+
: userIdOrUser;
|
|
26
27
|
|
|
27
28
|
const entity = await this.moduleRepository.findEntityById(
|
|
28
29
|
entityId,
|
|
@@ -34,9 +35,10 @@ class GetEntityOptionsById {
|
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
// Validate entity ownership
|
|
37
|
-
const isOwned =
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
const isOwned =
|
|
39
|
+
typeof userIdOrUser === 'object' && userIdOrUser?.ownsUserId
|
|
40
|
+
? userIdOrUser.ownsUserId(entity.userId)
|
|
41
|
+
: entity.userId?.toString() === userId?.toString();
|
|
40
42
|
|
|
41
43
|
if (!isOwned) {
|
|
42
44
|
throw new Error(
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GetModuleEntityById Use Case
|
|
3
|
+
* Retrieves a module entity by its ID
|
|
4
|
+
*/
|
|
5
|
+
class GetModuleEntityById {
|
|
6
|
+
constructor({ moduleRepository }) {
|
|
7
|
+
this.moduleRepository = moduleRepository;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async execute(entityId) {
|
|
11
|
+
const entity = await this.moduleRepository.findEntityById(entityId);
|
|
12
|
+
return entity;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
module.exports = { GetModuleEntityById };
|