@friggframework/core 2.0.0-next.104 → 2.0.0-next.105

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 (43) hide show
  1. package/admin-scripts/repositories/admin-script-execution-repository-interface.js +7 -2
  2. package/admin-scripts/repositories/admin-script-execution-repository-mongo.js +16 -6
  3. package/admin-scripts/repositories/admin-script-execution-repository-postgres.js +16 -6
  4. package/application/commands/admin-script-commands.js +2 -1
  5. package/application/commands/credential-commands.js +17 -0
  6. package/application/commands/integration-commands.js +14 -1
  7. package/application/commands/integration-mapping-commands.js +25 -0
  8. package/application/commands/report-commands.js +188 -0
  9. package/artifacts/repositories/artifact-repository-factory.js +19 -0
  10. package/artifacts/repositories/artifact-repository-interface.js +27 -0
  11. package/artifacts/repositories/artifact-repository-local.js +42 -0
  12. package/artifacts/repositories/artifact-repository-s3.js +61 -0
  13. package/credential/repositories/credential-active-type.js +32 -0
  14. package/credential/repositories/credential-repository-documentdb.js +51 -0
  15. package/credential/repositories/credential-repository-interface.js +15 -0
  16. package/credential/repositories/credential-repository-mongo.js +25 -0
  17. package/credential/repositories/credential-repository-postgres.js +25 -0
  18. package/database/documentdb-utils.js +56 -0
  19. package/handlers/app-definition-loader.js +3 -2
  20. package/index.js +8 -4
  21. package/integrations/repositories/integration-mapping-repository-documentdb.js +23 -0
  22. package/integrations/repositories/integration-mapping-repository-interface.js +14 -0
  23. package/integrations/repositories/integration-mapping-repository-mongo.js +22 -0
  24. package/integrations/repositories/integration-mapping-repository-postgres.js +28 -0
  25. package/integrations/repositories/integration-repository-documentdb.js +38 -0
  26. package/integrations/repositories/integration-repository-interface.js +16 -0
  27. package/integrations/repositories/integration-repository-mongo.js +36 -0
  28. package/integrations/repositories/integration-repository-postgres.js +40 -0
  29. package/integrations/repositories/report-id.js +13 -0
  30. package/package.json +7 -5
  31. package/reporting/README.md +109 -48
  32. package/reporting/builtin-reports.js +6 -0
  33. package/reporting/index.js +9 -13
  34. package/reporting/report-base.js +49 -0
  35. package/reporting/{use-cases/list-integrations-report.js → reports/integrations-report.js} +69 -37
  36. package/handlers/routers/reporting.js +0 -9
  37. package/reporting/reporting-router.js +0 -84
  38. package/reporting/repositories/reporting-repository-documentdb.js +0 -127
  39. package/reporting/repositories/reporting-repository-factory.js +0 -35
  40. package/reporting/repositories/reporting-repository-interface.js +0 -16
  41. package/reporting/repositories/reporting-repository-mongo.js +0 -54
  42. package/reporting/repositories/reporting-repository-postgres.js +0 -70
  43. package/reporting/use-cases/index.js +0 -6
@@ -1,127 +0,0 @@
1
- const { prisma } = require('../../database/prisma');
2
- const { toObjectId, fromObjectId } = require('../../database/documentdb-utils');
3
- const {
4
- ReportingRepositoryInterface,
5
- } = require('./reporting-repository-interface');
6
-
7
- const DRAIN_BATCH_SIZE = 1000;
8
- const MAX_BATCHES = 100000;
9
-
10
- // Drains cursors via getMore rather than reusing documentdb-utils.findMany/
11
- // aggregate, which return only the first batch (~101 docs) and would silently
12
- // truncate a deployment-wide report.
13
- class ReportingRepositoryDocumentDB extends ReportingRepositoryInterface {
14
- constructor() {
15
- super();
16
- this.prisma = prisma;
17
- }
18
-
19
- async findIntegrationsForReport({ status, userId } = {}) {
20
- const filter = {};
21
- if (status) filter.status = status;
22
- if (userId !== undefined && userId !== null) {
23
- const objectId = toObjectId(userId);
24
- // An invalid userId means no matches — must not fall through to an
25
- // unfiltered query that returns the whole deployment.
26
- if (!objectId) return [];
27
- filter.userId = objectId;
28
- }
29
-
30
- const docs = await this._findDrained('Integration', filter);
31
-
32
- return docs.map((doc) => {
33
- const errors = this._extractErrors(doc);
34
- return {
35
- id: fromObjectId(doc?._id),
36
- type: doc?.config?.type ?? null,
37
- status: doc?.status ?? null,
38
- userId: fromObjectId(doc?.userId) ?? null,
39
- version: doc?.version ?? null,
40
- errorCount: Array.isArray(errors) ? errors.length : 0,
41
- moduleCount: Array.isArray(doc?.entityIds)
42
- ? doc.entityIds.length
43
- : 0,
44
- createdAt: doc?.createdAt ?? null,
45
- updatedAt: doc?.updatedAt ?? null,
46
- };
47
- });
48
- }
49
-
50
- async countMappingsByIntegrationIds(ids = []) {
51
- const counts = new Map();
52
- if (!ids || ids.length === 0) return counts;
53
-
54
- // IntegrationMapping.integrationId is stored as a string in DocumentDB,
55
- // so match by string — an ObjectId $in would never match (always 0).
56
- const stringIds = ids.map(String);
57
-
58
- const rows = await this._aggregateDrained('IntegrationMapping', [
59
- { $match: { integrationId: { $in: stringIds } } },
60
- { $group: { _id: '$integrationId', count: { $sum: 1 } } },
61
- ]);
62
-
63
- for (const row of rows) {
64
- counts.set(String(row?._id), row?.count ?? 0);
65
- }
66
- return counts;
67
- }
68
-
69
- async _findDrained(collection, filter) {
70
- const first = await this.prisma.$runCommandRaw({
71
- find: collection,
72
- filter,
73
- batchSize: DRAIN_BATCH_SIZE,
74
- });
75
- return this._drain(collection, first);
76
- }
77
-
78
- async _aggregateDrained(collection, pipeline) {
79
- const first = await this.prisma.$runCommandRaw({
80
- aggregate: collection,
81
- pipeline,
82
- cursor: { batchSize: DRAIN_BATCH_SIZE },
83
- });
84
- return this._drain(collection, first);
85
- }
86
-
87
- async _drain(collection, firstResult) {
88
- const cursor = firstResult?.cursor || {};
89
- const docs = [...(cursor.firstBatch || [])];
90
- let cursorId = cursor.id;
91
- let batches = 0;
92
-
93
- while (this._cursorOpen(cursorId) && batches < MAX_BATCHES) {
94
- batches += 1;
95
- const next = await this.prisma.$runCommandRaw({
96
- getMore: cursorId,
97
- collection,
98
- batchSize: DRAIN_BATCH_SIZE,
99
- });
100
- const nextCursor = next?.cursor || {};
101
- const nextBatch = nextCursor.nextBatch || [];
102
- docs.push(...nextBatch);
103
- cursorId = nextCursor.id;
104
- if (nextBatch.length === 0) break;
105
- }
106
- return docs;
107
- }
108
-
109
- _cursorOpen(id) {
110
- if (id === undefined || id === null) return false;
111
- if (typeof id === 'number') return id !== 0;
112
- if (typeof id === 'bigint') return id !== 0n;
113
- // Extended JSON can surface a 64-bit cursor id as { $numberLong: "..." }.
114
- if (typeof id === 'object' && id.$numberLong !== undefined) {
115
- return id.$numberLong !== '0';
116
- }
117
- return String(id) !== '0';
118
- }
119
-
120
- _extractErrors(doc) {
121
- if (Array.isArray(doc?.errors)) return doc.errors;
122
- if (Array.isArray(doc?.messages?.errors)) return doc.messages.errors;
123
- return [];
124
- }
125
- }
126
-
127
- module.exports = { ReportingRepositoryDocumentDB };
@@ -1,35 +0,0 @@
1
- const { ReportingRepositoryMongo } = require('./reporting-repository-mongo');
2
- const {
3
- ReportingRepositoryPostgres,
4
- } = require('./reporting-repository-postgres');
5
- const {
6
- ReportingRepositoryDocumentDB,
7
- } = require('./reporting-repository-documentdb');
8
- const config = require('../../database/config');
9
-
10
- function createReportingRepository() {
11
- const dbType = config.DB_TYPE;
12
-
13
- switch (dbType) {
14
- case 'mongodb':
15
- return new ReportingRepositoryMongo();
16
-
17
- case 'postgresql':
18
- return new ReportingRepositoryPostgres();
19
-
20
- case 'documentdb':
21
- return new ReportingRepositoryDocumentDB();
22
-
23
- default:
24
- throw new Error(
25
- `Unsupported database type: ${dbType}. Supported values: 'mongodb', 'documentdb', 'postgresql'`
26
- );
27
- }
28
- }
29
-
30
- module.exports = {
31
- createReportingRepository,
32
- ReportingRepositoryMongo,
33
- ReportingRepositoryPostgres,
34
- ReportingRepositoryDocumentDB,
35
- };
@@ -1,16 +0,0 @@
1
- class ReportingRepositoryInterface {
2
- // returns: [{ id, type, status, userId, version, errorCount, moduleCount, createdAt, updatedAt }]
3
- async findIntegrationsForReport(filter) {
4
- throw new Error(
5
- 'Method findIntegrationsForReport must be implemented by subclass'
6
- );
7
- }
8
-
9
- async countMappingsByIntegrationIds(ids) {
10
- throw new Error(
11
- 'Method countMappingsByIntegrationIds must be implemented by subclass'
12
- );
13
- }
14
- }
15
-
16
- module.exports = { ReportingRepositoryInterface };
@@ -1,54 +0,0 @@
1
- const { prisma } = require('../../database/prisma');
2
- const {
3
- ReportingRepositoryInterface,
4
- } = require('./reporting-repository-interface');
5
-
6
- class ReportingRepositoryMongo extends ReportingRepositoryInterface {
7
- constructor() {
8
- super();
9
- this.prisma = prisma;
10
- }
11
-
12
- async findIntegrationsForReport({ status, userId } = {}) {
13
- const where = {};
14
- if (status) where.status = status;
15
- if (userId !== undefined && userId !== null) where.userId = userId;
16
-
17
- const integrations = await this.prisma.integration.findMany({
18
- where,
19
- include: { entities: { select: { id: true } } },
20
- });
21
-
22
- return integrations.map((integration) => ({
23
- id: integration.id,
24
- type: integration.config?.type ?? null,
25
- status: integration.status ?? null,
26
- userId: integration.userId ?? null,
27
- version: integration.version ?? null,
28
- errorCount: Array.isArray(integration.errors)
29
- ? integration.errors.length
30
- : 0,
31
- moduleCount: integration.entities?.length ?? 0,
32
- createdAt: integration.createdAt ?? null,
33
- updatedAt: integration.updatedAt ?? null,
34
- }));
35
- }
36
-
37
- async countMappingsByIntegrationIds(ids = []) {
38
- const counts = new Map();
39
- if (!ids || ids.length === 0) return counts;
40
-
41
- const groups = await this.prisma.integrationMapping.groupBy({
42
- by: ['integrationId'],
43
- where: { integrationId: { in: ids } },
44
- _count: { _all: true },
45
- });
46
-
47
- for (const group of groups) {
48
- counts.set(group.integrationId, group._count._all);
49
- }
50
- return counts;
51
- }
52
- }
53
-
54
- module.exports = { ReportingRepositoryMongo };
@@ -1,70 +0,0 @@
1
- const { prisma } = require('../../database/prisma');
2
- const {
3
- ReportingRepositoryInterface,
4
- } = require('./reporting-repository-interface');
5
-
6
- class ReportingRepositoryPostgres extends ReportingRepositoryInterface {
7
- constructor() {
8
- super();
9
- this.prisma = prisma;
10
- }
11
-
12
- async findIntegrationsForReport({ status, userId } = {}) {
13
- const where = {};
14
- if (status) where.status = status;
15
- if (userId !== undefined && userId !== null) {
16
- where.userId = this._convertId(userId);
17
- }
18
-
19
- const integrations = await this.prisma.integration.findMany({
20
- where,
21
- include: { entities: { select: { id: true } } },
22
- });
23
-
24
- return integrations.map((integration) => ({
25
- id: integration.id?.toString(),
26
- type: integration.config?.type ?? null,
27
- status: integration.status ?? null,
28
- userId: integration.userId?.toString() ?? null,
29
- version: integration.version ?? null,
30
- errorCount: Array.isArray(integration.errors)
31
- ? integration.errors.length
32
- : 0,
33
- moduleCount: integration.entities?.length ?? 0,
34
- createdAt: integration.createdAt ?? null,
35
- updatedAt: integration.updatedAt ?? null,
36
- }));
37
- }
38
-
39
- async countMappingsByIntegrationIds(ids = []) {
40
- const counts = new Map();
41
- if (!ids || ids.length === 0) return counts;
42
-
43
- const intIds = ids.map((id) => this._convertId(id));
44
- const groups = await this.prisma.integrationMapping.groupBy({
45
- by: ['integrationId'],
46
- where: { integrationId: { in: intIds } },
47
- _count: { _all: true },
48
- });
49
-
50
- for (const group of groups) {
51
- counts.set(group.integrationId?.toString(), group._count._all);
52
- }
53
- return counts;
54
- }
55
-
56
- _convertId(id) {
57
- if (id === null || id === undefined) return id;
58
- // Reject anything that isn't an exact integer — parseInt would coerce
59
- // '12abc'/'12.9' to 12 and return the wrong record.
60
- const str = String(id).trim();
61
- if (!/^-?\d+$/.test(str)) {
62
- throw new TypeError(
63
- `Invalid ID: ${id} cannot be converted to integer`
64
- );
65
- }
66
- return Number.parseInt(str, 10);
67
- }
68
- }
69
-
70
- module.exports = { ReportingRepositoryPostgres };
@@ -1,6 +0,0 @@
1
- const {
2
- ListIntegrationsReport,
3
- SCHEMA_VERSION,
4
- } = require('./list-integrations-report');
5
-
6
- module.exports = { ListIntegrationsReport, SCHEMA_VERSION };