@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.
- package/admin-scripts/repositories/admin-script-execution-repository-interface.js +7 -2
- package/admin-scripts/repositories/admin-script-execution-repository-mongo.js +16 -6
- package/admin-scripts/repositories/admin-script-execution-repository-postgres.js +16 -6
- package/application/commands/admin-script-commands.js +2 -1
- package/application/commands/credential-commands.js +17 -0
- package/application/commands/integration-commands.js +14 -1
- package/application/commands/integration-mapping-commands.js +25 -0
- package/application/commands/report-commands.js +188 -0
- package/artifacts/repositories/artifact-repository-factory.js +19 -0
- package/artifacts/repositories/artifact-repository-interface.js +27 -0
- package/artifacts/repositories/artifact-repository-local.js +42 -0
- package/artifacts/repositories/artifact-repository-s3.js +61 -0
- package/credential/repositories/credential-active-type.js +32 -0
- package/credential/repositories/credential-repository-documentdb.js +51 -0
- package/credential/repositories/credential-repository-interface.js +15 -0
- package/credential/repositories/credential-repository-mongo.js +25 -0
- package/credential/repositories/credential-repository-postgres.js +25 -0
- package/database/documentdb-utils.js +56 -0
- package/handlers/app-definition-loader.js +3 -2
- package/index.js +8 -4
- package/integrations/repositories/integration-mapping-repository-documentdb.js +23 -0
- package/integrations/repositories/integration-mapping-repository-interface.js +14 -0
- package/integrations/repositories/integration-mapping-repository-mongo.js +22 -0
- package/integrations/repositories/integration-mapping-repository-postgres.js +28 -0
- package/integrations/repositories/integration-repository-documentdb.js +38 -0
- package/integrations/repositories/integration-repository-interface.js +16 -0
- package/integrations/repositories/integration-repository-mongo.js +36 -0
- package/integrations/repositories/integration-repository-postgres.js +40 -0
- package/integrations/repositories/report-id.js +13 -0
- package/package.json +7 -5
- package/reporting/README.md +109 -48
- package/reporting/builtin-reports.js +6 -0
- package/reporting/index.js +9 -13
- package/reporting/report-base.js +49 -0
- package/reporting/{use-cases/list-integrations-report.js → reports/integrations-report.js} +69 -37
- package/handlers/routers/reporting.js +0 -9
- package/reporting/reporting-router.js +0 -84
- package/reporting/repositories/reporting-repository-documentdb.js +0 -127
- package/reporting/repositories/reporting-repository-factory.js +0 -35
- package/reporting/repositories/reporting-repository-interface.js +0 -16
- package/reporting/repositories/reporting-repository-mongo.js +0 -54
- package/reporting/repositories/reporting-repository-postgres.js +0 -70
- 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 };
|