streamby-core 0.37.0 → 0.39.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 (50) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/LICENSE +661 -661
  3. package/README.md +573 -512
  4. package/dist/adapters/database/connectionManager.js +124 -124
  5. package/dist/adapters/database/sql.js +1 -1
  6. package/dist/adapters/storage/s3.d.ts +3 -2
  7. package/dist/adapters/storage/s3.js +18 -5
  8. package/dist/mcp/server.js +12 -0
  9. package/dist/mcp/tools.d.ts +2 -0
  10. package/dist/mcp/tools.js +107 -14
  11. package/dist/mcp/workflowNodes.d.ts +24 -0
  12. package/dist/mcp/workflowNodes.js +48 -0
  13. package/dist/middleware/createRouter.js +2 -0
  14. package/dist/middleware/routes/apiConnection.d.ts +3 -0
  15. package/dist/middleware/routes/apiConnection.js +100 -0
  16. package/dist/middleware/routes/credential.d.ts +3 -0
  17. package/dist/middleware/routes/credential.js +80 -0
  18. package/dist/middleware/routes/deliverable.d.ts +3 -0
  19. package/dist/middleware/routes/deliverable.js +131 -0
  20. package/dist/middleware/routes/export.js +18 -0
  21. package/dist/middleware/routes/production.js +60 -67
  22. package/dist/middleware/routes/project.js +39 -11
  23. package/dist/middleware/routes/storage.js +115 -24
  24. package/dist/models/Model.js +9 -9
  25. package/dist/services/apiConnection.d.ts +18 -0
  26. package/dist/services/apiConnection.js +65 -0
  27. package/dist/services/apiTokenPermissions.js +7 -3
  28. package/dist/services/assetVersions.d.ts +48 -0
  29. package/dist/services/assetVersions.js +84 -0
  30. package/dist/services/credential.d.ts +8 -0
  31. package/dist/services/credential.js +70 -0
  32. package/dist/services/deliverables.d.ts +26 -0
  33. package/dist/services/deliverables.js +55 -0
  34. package/dist/services/mediaProcessor.js +3 -1
  35. package/dist/services/pipeline.d.ts +2 -0
  36. package/dist/services/pipeline.js +292 -0
  37. package/dist/services/production.d.ts +2 -0
  38. package/dist/services/production.js +13 -0
  39. package/dist/services/productionFields.d.ts +16 -0
  40. package/dist/services/productionFields.js +80 -0
  41. package/dist/services/signedUrls.d.ts +6 -0
  42. package/dist/services/signedUrls.js +9 -0
  43. package/dist/types/index.d.ts +7 -2
  44. package/dist/utils/crypto.d.ts +3 -0
  45. package/dist/utils/crypto.js +32 -0
  46. package/dist/utils/nosqlDb.d.ts +2 -0
  47. package/dist/utils/nosqlDb.js +11 -0
  48. package/dist/utils/sanitize.d.ts +1 -0
  49. package/dist/utils/sanitize.js +14 -0
  50. package/package.json +1 -1
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.newShotNode = void 0;
7
+ exports.ensureWorkflowNode = ensureWorkflowNode;
8
+ const crypto_1 = __importDefault(require("crypto"));
9
+ const manager_1 = require("../models/manager");
10
+ const auth_1 = require("../utils/auth");
11
+ const auth_2 = require("../services/auth");
12
+ // The node types that make a workflow's production section (as the UI groups them).
13
+ const PRODUCTION_NODE_TYPES = new Set(['shotNode', 'assemblyNode', 'masterNode']);
14
+ /** A Shot node, as the UI makes one dropped on the canvas without a position. */
15
+ const newShotNode = () => ({
16
+ id: `shotNode-${crypto_1.default.randomUUID()}`,
17
+ type: 'shotNode',
18
+ position: { x: 240 + Math.random() * 60, y: 300 + Math.random() * 40 },
19
+ data: { label: 'Shot', subtitle: 'Raw video clip', bgColor: '#0e2537', iconColor: '#38B6FF' },
20
+ });
21
+ exports.newShotNode = newShotNode;
22
+ /**
23
+ * Makes sure a project's workflow has what `requirement` needs, adding it (through the REST
24
+ * API, as the caller) if it's missing. An error to answer with, or null to go on. A project
25
+ * the caller doesn't reach is left alone: the call that follows answers for it.
26
+ */
27
+ async function ensureWorkflowNode(requirement, projectId, auth, api) {
28
+ if (requirement !== 'production' || !projectId)
29
+ return null;
30
+ if (!(0, auth_2.scopeReachesProject)(auth.apiToken, projectId))
31
+ return null;
32
+ const project = await (0, manager_1.getModel)('projects').findOne({ _id: projectId });
33
+ if (!project || !(0, auth_1.activeMemberOf)(project, auth.userId))
34
+ return null;
35
+ const schema = project.workflow?.nodeSchema ?? null;
36
+ const nodes = Array.isArray(schema?.nodes) ? schema.nodes : [];
37
+ if (nodes.some(node => PRODUCTION_NODE_TYPES.has(node?.type)))
38
+ return null;
39
+ const answer = await api({
40
+ method: 'PATCH',
41
+ path: `/projects/${encodeURIComponent(projectId)}/workflow`,
42
+ body: { nodeSchema: { ...(schema ?? {}), nodes: [...nodes, (0, exports.newShotNode)()], edges: Array.isArray(schema?.edges) ? schema.edges : [] } },
43
+ });
44
+ if (answer.status >= 200 && answer.status < 300)
45
+ return null;
46
+ const message = answer.body?.message ?? answer.body?.error;
47
+ return `Couldn't add a production node to the project's workflow: ${typeof message === 'string' ? message : `StreamBy answered ${answer.status}`}`;
48
+ }
@@ -38,6 +38,7 @@ const production_1 = require("./routes/production");
38
38
  const rights_1 = require("./routes/rights");
39
39
  const workflow_1 = require("./routes/workflow");
40
40
  const pipeline_1 = require("./routes/pipeline");
41
+ const deliverable_1 = require("./routes/deliverable");
41
42
  function createStreamByRouter(config) {
42
43
  const router = express_1.default.Router();
43
44
  if (config.encrypt)
@@ -134,5 +135,6 @@ function createStreamByRouter(config) {
134
135
  router.use((0, rights_1.rightsRouter)(config));
135
136
  router.use((0, workflow_1.workflowRouter)(config));
136
137
  router.use((0, pipeline_1.pipelineRouter)(config));
138
+ router.use((0, deliverable_1.deliverableRouter)(config));
137
139
  return router;
138
140
  }
@@ -0,0 +1,3 @@
1
+ import { Router } from 'express';
2
+ import { StreamByConfig } from '../../types';
3
+ export declare function apiConnectionRouter(config: StreamByConfig): Router;
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.apiConnectionRouter = apiConnectionRouter;
4
+ const express_1 = require("express");
5
+ const manager_1 = require("../../models/manager");
6
+ const auth_1 = require("../../utils/auth");
7
+ const apiConnection_1 = require("../../services/apiConnection");
8
+ const VALID_METHODS = ['GET', 'POST', 'PATCH', 'PUT', 'DELETE'];
9
+ function apiConnectionRouter(config) {
10
+ const router = (0, express_1.Router)();
11
+ const Project = (0, manager_1.getModel)('projects');
12
+ // List API connections for a project
13
+ router.get('/projects/:id/api/connections', async (req, res) => {
14
+ try {
15
+ const auth = req.auth;
16
+ const projectId = req.params.id;
17
+ const project = await Project.findOne({ _id: projectId });
18
+ if (!project) {
19
+ return res.status(404).json({ message: 'Project not found' });
20
+ }
21
+ if (!(0, auth_1.isProjectMember)(project, auth.userId)) {
22
+ return res.status(403).json({ message: 'Unauthorized project access' });
23
+ }
24
+ return res.status(200).json({ data: project.apiConnections || [] });
25
+ }
26
+ catch (err) {
27
+ res.status(500).json({ message: 'Failed to fetch API connections', details: err.message });
28
+ }
29
+ });
30
+ // Add a new API connection to a project
31
+ router.post('/projects/:id/api/connections', async (req, res) => {
32
+ try {
33
+ const auth = req.auth;
34
+ if (auth.role !== 'admin' && auth.role !== 'editor') {
35
+ return res.status(403).json({ message: 'Permission denied' });
36
+ }
37
+ const projectId = req.params.id;
38
+ const { name, baseUrl, method, description, credentialId, prefix } = req.body;
39
+ if (!name || !baseUrl) {
40
+ return res.status(400).json({ message: 'name and baseUrl are required' });
41
+ }
42
+ if (!VALID_METHODS.includes(method)) {
43
+ return res.status(400).json({ message: `method must be one of: ${VALID_METHODS.join(', ')}` });
44
+ }
45
+ const project = await Project.findOne({ _id: projectId });
46
+ if (!project) {
47
+ return res.status(404).json({ message: 'Project not found' });
48
+ }
49
+ if (!(0, auth_1.isProjectMember)(project, auth.userId)) {
50
+ return res.status(403).json({ message: 'Unauthorized project access' });
51
+ }
52
+ if (credentialId) {
53
+ const credExists = project.credentials?.some((c) => c.id === credentialId);
54
+ if (!credExists) {
55
+ return res.status(400).json({ message: 'Credential not found in project' });
56
+ }
57
+ }
58
+ const connection = await (0, apiConnection_1.addApiConnection)(config, projectId, {
59
+ name,
60
+ baseUrl,
61
+ method,
62
+ prefix,
63
+ ...(description !== undefined && { description }),
64
+ ...(credentialId !== undefined && { credentialId }),
65
+ });
66
+ return res.status(201).json({ data: connection });
67
+ }
68
+ catch (err) {
69
+ res.status(500).json({ message: 'Failed to add API connection', details: err.message });
70
+ }
71
+ });
72
+ // Delete an API connection from a project
73
+ router.delete('/projects/:id/api/connections/:connectionId', async (req, res) => {
74
+ try {
75
+ const auth = req.auth;
76
+ if (auth.role !== 'admin' && auth.role !== 'editor') {
77
+ return res.status(403).json({ message: 'Permission denied' });
78
+ }
79
+ const projectId = req.params.id;
80
+ const { connectionId } = req.params;
81
+ const project = await Project.findOne({ _id: projectId });
82
+ if (!project) {
83
+ return res.status(404).json({ message: 'Project not found' });
84
+ }
85
+ if (!(0, auth_1.isProjectMember)(project, auth.userId)) {
86
+ return res.status(403).json({ message: 'Unauthorized project access' });
87
+ }
88
+ const exists = project.apiConnections?.some((c) => c.id === connectionId);
89
+ if (!exists) {
90
+ return res.status(404).json({ message: 'API connection not found' });
91
+ }
92
+ await (0, apiConnection_1.deleteApiConnection)(config, projectId, connectionId);
93
+ return res.status(200).json({ message: 'API connection deleted successfully.' });
94
+ }
95
+ catch (err) {
96
+ res.status(500).json({ message: 'Failed to delete API connection', details: err.message });
97
+ }
98
+ });
99
+ return router;
100
+ }
@@ -0,0 +1,3 @@
1
+ import { Router } from 'express';
2
+ import { StreamByConfig } from '../../types';
3
+ export declare function credentialRouter(config: StreamByConfig): Router;
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.credentialRouter = credentialRouter;
4
+ const express_1 = require("express");
5
+ const manager_1 = require("../../models/manager");
6
+ const auth_1 = require("../../utils/auth");
7
+ const sanitize_1 = require("../../utils/sanitize");
8
+ const credential_1 = require("../../services/credential");
9
+ function credentialRouter(config) {
10
+ const router = (0, express_1.Router)();
11
+ const Project = (0, manager_1.getModel)('projects');
12
+ // Add a new credential to a project
13
+ router.post('/projects/:id/credentials', async (req, res) => {
14
+ try {
15
+ const auth = req.auth;
16
+ if (auth.role !== 'admin' && auth.role !== 'editor') {
17
+ return res.status(403).json({ message: 'Permission denied' });
18
+ }
19
+ const projectId = req.params.id;
20
+ const { id, key, value } = req.body;
21
+ if (!key || !value) {
22
+ return res.status(400).json({ message: 'Missing credential key or value' });
23
+ }
24
+ const project = await Project.findOne({ _id: projectId });
25
+ if (!project || !(0, auth_1.isProjectMember)(project, auth.userId)) {
26
+ return res.status(403).json({ message: 'Unauthorized project access' });
27
+ }
28
+ const updatedProject = await (0, credential_1.addCredential)(config, projectId, { id, key, value });
29
+ res.status(201).json({ message: 'Credential added successfully', project: (0, sanitize_1.sanitizeProject)(updatedProject) });
30
+ }
31
+ catch (err) {
32
+ res.status(500).json({ message: 'Failed to add credential', details: err.message });
33
+ }
34
+ });
35
+ // Update an existing credential in a project
36
+ router.patch('/projects/:id/credentials/:credentialId', async (req, res) => {
37
+ try {
38
+ const auth = req.auth;
39
+ if (auth.role !== 'admin' && auth.role !== 'editor') {
40
+ return res.status(403).json({ message: 'Permission denied' });
41
+ }
42
+ const projectId = req.params.id;
43
+ const credentialId = req.params.credentialId;
44
+ const { key, value } = req.body;
45
+ if (!key && !value) {
46
+ return res.status(400).json({ message: 'No update fields provided' });
47
+ }
48
+ const project = await Project.findOne({ _id: projectId });
49
+ if (!project || !(0, auth_1.isProjectMember)(project, auth.userId)) {
50
+ return res.status(403).json({ message: 'Unauthorized project access' });
51
+ }
52
+ const updatedProject = await (0, credential_1.updateCredential)(config, projectId, credentialId, { key, value });
53
+ res.status(200).json({ message: 'Credential updated successfully', project: (0, sanitize_1.sanitizeProject)(updatedProject) });
54
+ }
55
+ catch (err) {
56
+ res.status(500).json({ message: 'Failed to update credential', details: err.message });
57
+ }
58
+ });
59
+ // Delete a credential from a project
60
+ router.delete('/projects/:id/credentials/:credentialId', async (req, res) => {
61
+ try {
62
+ const auth = req.auth;
63
+ if (auth.role !== 'admin' && auth.role !== 'editor') {
64
+ return res.status(403).json({ message: 'Permission denied' });
65
+ }
66
+ const projectId = req.params.id;
67
+ const credentialId = req.params.credentialId;
68
+ const project = await Project.findOne({ _id: projectId });
69
+ if (!project || !(0, auth_1.isProjectMember)(project, auth.userId)) {
70
+ return res.status(403).json({ message: 'Unauthorized project access' });
71
+ }
72
+ const updatedProject = await (0, credential_1.deleteCredential)(config, projectId, credentialId);
73
+ res.status(200).json({ message: 'Credential deleted successfully', project: (0, sanitize_1.sanitizeProject)(updatedProject) });
74
+ }
75
+ catch (err) {
76
+ res.status(500).json({ message: 'Failed to delete credential', details: err.message });
77
+ }
78
+ });
79
+ return router;
80
+ }
@@ -0,0 +1,3 @@
1
+ import { Router } from 'express';
2
+ import { StreamByConfig } from '../../types';
3
+ export declare function deliverableRouter(_config: StreamByConfig): Router;
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deliverableRouter = deliverableRouter;
4
+ const express_1 = require("express");
5
+ const manager_1 = require("../../models/manager");
6
+ const auth_1 = require("../../utils/auth");
7
+ const nosqlDb_1 = require("../../utils/nosqlDb");
8
+ const assetVersions_1 = require("../../services/assetVersions");
9
+ const deliverables_1 = require("../../services/deliverables");
10
+ const MAX_NOTE = 1000;
11
+ // A project's deliverables (see services/deliverables): marked, listed and removed. Removing
12
+ // one never deletes its asset.
13
+ function deliverableRouter(_config) {
14
+ const router = (0, express_1.Router)();
15
+ const Project = (0, manager_1.getModel)('projects');
16
+ const exportsOf = (project) => project.exports ?? [];
17
+ // What a list shows of each: its asset's name and kind, its version's number, and the name
18
+ // of the shot or export it's for.
19
+ const describe = async (project, deliverables) => {
20
+ const db = (0, nosqlDb_1.nosqlDb)();
21
+ const assetIds = [...new Set(deliverables.map(d => d.assetId))];
22
+ const shotIds = [...new Set(deliverables.map(d => d.shotId).filter(Boolean))];
23
+ const versionIds = [...new Set(deliverables.map(d => d.versionId).filter(Boolean))];
24
+ const [files, shots, versions] = db
25
+ ? await Promise.all([
26
+ db.collection('storage_files').find({ projectId: project._id?.toString() ?? project.id, fileId: { $in: assetIds } }).toArray(),
27
+ shotIds.length ? db.collection('production_shots').find({ id: { $in: shotIds } }).toArray() : [],
28
+ versionIds.length ? db.collection('asset_versions').find({ versionId: { $in: versionIds } }).toArray() : [],
29
+ ])
30
+ : [[], [], []];
31
+ return deliverables.map(d => {
32
+ const file = files.find((f) => f.fileId === d.assetId);
33
+ const version = versions.find((v) => v.versionId === d.versionId);
34
+ return {
35
+ ...d,
36
+ asset: file ? { displayName: file.displayName, category: file.category, contentType: file.contentType ?? null } : null,
37
+ version: version ? version.version : null,
38
+ shotName: d.shotId ? shots.find((s) => s.id === d.shotId)?.name ?? null : null,
39
+ exportName: d.exportId ? exportsOf(project).find((e) => e.id?.toString() === d.exportId)?.name ?? null : null,
40
+ };
41
+ });
42
+ };
43
+ router.get('/projects/:projectId/deliverables', async (req, res) => {
44
+ try {
45
+ const auth = req.auth;
46
+ const { projectId } = req.params;
47
+ const { shotId, exportId } = req.query;
48
+ const project = await Project.findOne({ _id: projectId });
49
+ if (!project)
50
+ return res.status(404).json({ message: 'Project not found' });
51
+ if (!(0, auth_1.isProjectMember)(project, auth.userId))
52
+ return res.status(403).json({ message: 'Unauthorized' });
53
+ const deliverables = await (0, deliverables_1.listDeliverables)(projectId, { shotId, exportId });
54
+ res.json({ deliverables: await describe(project, deliverables) });
55
+ }
56
+ catch (err) {
57
+ res.status(500).json({ message: 'Failed to list deliverables', details: err.message });
58
+ }
59
+ });
60
+ router.post('/projects/:projectId/deliverables', async (req, res) => {
61
+ try {
62
+ const auth = req.auth;
63
+ const { projectId } = req.params;
64
+ const { assetId, versionId, shotId, exportId, note } = req.body ?? {};
65
+ if (typeof assetId !== 'string' || !assetId)
66
+ return res.status(400).json({ message: 'assetId is required' });
67
+ if (versionId !== undefined && versionId !== null && typeof versionId !== 'string') {
68
+ return res.status(400).json({ message: 'versionId must be a string' });
69
+ }
70
+ const forShot = typeof shotId === 'string' && shotId !== '';
71
+ const forExport = typeof exportId === 'string' && exportId !== '';
72
+ if (forShot === forExport)
73
+ return res.status(400).json({ message: 'A deliverable is for a shot (shotId) or for an export (exportId), one of them' });
74
+ if (note !== undefined && note !== null && (typeof note !== 'string' || note.length > MAX_NOTE)) {
75
+ return res.status(400).json({ message: `note must be a string of at most ${MAX_NOTE} characters` });
76
+ }
77
+ const project = await Project.findOne({ _id: projectId });
78
+ if (!project)
79
+ return res.status(404).json({ message: 'Project not found' });
80
+ if (!(0, auth_1.canEditProject)(project, auth.userId))
81
+ return res.status(403).json({ message: 'Unauthorized' });
82
+ const db = (0, nosqlDb_1.nosqlDb)();
83
+ if (!db)
84
+ return res.status(500).json({ message: 'Database not available' });
85
+ if (!(await db.collection('storage_files').findOne({ fileId: assetId, projectId }))) {
86
+ return res.status(404).json({ message: 'Asset not found' });
87
+ }
88
+ if (versionId && !(await (0, assetVersions_1.findVersion)(projectId, assetId, versionId))) {
89
+ return res.status(404).json({ message: 'Version not found' });
90
+ }
91
+ if (forShot && !(await db.collection('production_shots').findOne({ id: shotId, projectId }))) {
92
+ return res.status(404).json({ message: 'Shot not found' });
93
+ }
94
+ if (forExport && !exportsOf(project).some((e) => e.id?.toString() === exportId)) {
95
+ return res.status(404).json({ message: 'Export not found' });
96
+ }
97
+ const deliverable = await (0, deliverables_1.createDeliverable)({
98
+ projectId,
99
+ assetId,
100
+ versionId: versionId || null,
101
+ shotId: forShot ? shotId : null,
102
+ exportId: forExport ? exportId : null,
103
+ note: note || null,
104
+ createdBy: auth.userId,
105
+ });
106
+ const [described] = await describe(project, [deliverable]);
107
+ res.status(201).json({ deliverable: described });
108
+ }
109
+ catch (err) {
110
+ res.status(500).json({ message: 'Failed to mark the deliverable', details: err.message });
111
+ }
112
+ });
113
+ router.delete('/projects/:projectId/deliverables/:deliverableId', async (req, res) => {
114
+ try {
115
+ const auth = req.auth;
116
+ const { projectId, deliverableId } = req.params;
117
+ const project = await Project.findOne({ _id: projectId });
118
+ if (!project)
119
+ return res.status(404).json({ message: 'Project not found' });
120
+ if (!(0, auth_1.canEditProject)(project, auth.userId))
121
+ return res.status(403).json({ message: 'Unauthorized' });
122
+ if (!(await (0, deliverables_1.deleteDeliverable)(projectId, deliverableId)))
123
+ return res.status(404).json({ message: 'Deliverable not found' });
124
+ res.json({ message: 'Deliverable removed' });
125
+ }
126
+ catch (err) {
127
+ res.status(500).json({ message: 'Failed to remove the deliverable', details: err.message });
128
+ }
129
+ });
130
+ return router;
131
+ }
@@ -2,6 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.exportRouter = exportRouter;
4
4
  const express_1 = require("express");
5
+ const deliverables_1 = require("../../services/deliverables");
6
+ const sanitize_1 = require("../../utils/sanitize");
5
7
  const manager_1 = require("../../models/manager");
6
8
  const auth_1 = require("../../utils/auth");
7
9
  const export_1 = require("../../services/export");
@@ -60,6 +62,21 @@ const DEFAULT_NODE_SCHEMA = {
60
62
  function exportRouter(config) {
61
63
  const router = (0, express_1.Router)();
62
64
  const Project = (0, manager_1.getModel)('projects');
65
+ // ─── A project's exports, on their own ────────────────────────────────────
66
+ router.get('/projects/:id/exports', async (req, res) => {
67
+ try {
68
+ const auth = req.auth;
69
+ const project = await Project.findOne({ _id: req.params.id });
70
+ if (!project)
71
+ return res.status(404).json({ message: 'Project not found' });
72
+ if (!(0, auth_1.isProjectMember)(project, auth.userId))
73
+ return res.status(403).json({ message: 'Unauthorized access' });
74
+ return res.status(200).json({ data: (0, sanitize_1.exportSummaries)(project.exports) });
75
+ }
76
+ catch (err) {
77
+ res.status(500).json({ message: 'Failed to fetch exports', details: err.message });
78
+ }
79
+ });
63
80
  router.get('/projects/:id/exports/:export_id', async (req, res) => {
64
81
  try {
65
82
  const auth = await config.authProvider(req);
@@ -292,6 +309,7 @@ function exportRouter(config) {
292
309
  return res.status(404).json({ message: 'Export not found in this project' });
293
310
  }
294
311
  await (0, export_1.deleteExport)(config, projectId, exportId, project.dbType);
312
+ await (0, deliverables_1.deleteDeliverablesOf)(projectId, { exportId });
295
313
  res.status(200).json({ message: 'Export deleted successfully' });
296
314
  }
297
315
  catch (err) {