streamby-core 0.32.1 → 0.34.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 (55) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/LICENSE +661 -0
  3. package/README.md +53 -2
  4. package/dist/middleware/createRouter.js +17 -2
  5. package/dist/middleware/routes/ai.js +3 -3
  6. package/dist/middleware/routes/connection.js +3 -12
  7. package/dist/middleware/routes/dbConnection.js +7 -26
  8. package/dist/middleware/routes/distribution.js +12 -5
  9. package/dist/middleware/routes/export.js +5 -4
  10. package/dist/middleware/routes/media.js +23 -10
  11. package/dist/middleware/routes/member.js +3 -12
  12. package/dist/middleware/routes/{credential.d.ts → oauth.d.ts} +1 -1
  13. package/dist/middleware/routes/oauth.js +101 -0
  14. package/dist/middleware/routes/pipeline.js +3 -3
  15. package/dist/middleware/routes/production.js +9 -9
  16. package/dist/middleware/routes/project.js +24 -31
  17. package/dist/middleware/routes/renderFarm.js +13 -6
  18. package/dist/middleware/routes/review.js +4 -4
  19. package/dist/middleware/routes/rights.js +1 -1
  20. package/dist/middleware/routes/storage.js +21 -15
  21. package/dist/middleware/routes/storageConnection.js +2 -8
  22. package/dist/middleware/routes/userIntegration.js +17 -2
  23. package/dist/middleware/routes/workflow.js +1 -1
  24. package/dist/services/auth.d.ts +1 -2
  25. package/dist/services/auth.js +9 -11
  26. package/dist/services/connectionResolver.js +6 -6
  27. package/dist/services/executor.d.ts +4 -1
  28. package/dist/services/executor.js +63 -6
  29. package/dist/services/oauthClient.d.ts +10 -0
  30. package/dist/services/oauthClient.js +134 -0
  31. package/dist/services/projectIntegration.d.ts +4 -1
  32. package/dist/services/projectIntegration.js +13 -3
  33. package/dist/services/reencryptCredentials.d.ts +5 -0
  34. package/dist/services/reencryptCredentials.js +74 -0
  35. package/dist/services/userIntegration.d.ts +23 -3
  36. package/dist/services/userIntegration.js +130 -7
  37. package/dist/types/index.d.ts +31 -3
  38. package/dist/utils/auth.d.ts +15 -1
  39. package/dist/utils/auth.js +21 -6
  40. package/dist/utils/encryption.d.ts +6 -1
  41. package/dist/utils/encryption.js +80 -27
  42. package/dist/utils/sanitize.d.ts +6 -0
  43. package/dist/utils/sanitize.js +18 -1
  44. package/dist/utils/serviceEndpoints.d.ts +2 -0
  45. package/dist/utils/serviceEndpoints.js +26 -0
  46. package/package.json +4 -3
  47. package/dist/middleware/routes/apiConnection.d.ts +0 -3
  48. package/dist/middleware/routes/apiConnection.js +0 -100
  49. package/dist/middleware/routes/credential.js +0 -80
  50. package/dist/services/apiConnection.d.ts +0 -18
  51. package/dist/services/apiConnection.js +0 -65
  52. package/dist/services/credential.d.ts +0 -8
  53. package/dist/services/credential.js +0 -70
  54. package/dist/services/pipeline.d.ts +0 -2
  55. package/dist/services/pipeline.js +0 -292
@@ -1,100 +0,0 @@
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
- }
@@ -1,80 +0,0 @@
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
- }
@@ -1,18 +0,0 @@
1
- import { StreamByConfig, ApiConnection, ApiConnectionMethod } from '../types';
2
- export declare function addApiConnection(config: StreamByConfig, projectId: string, data: {
3
- name: string;
4
- apiUrl: string;
5
- method: ApiConnectionMethod;
6
- prefix?: string;
7
- description?: string;
8
- credentialId?: string;
9
- }): Promise<ApiConnection>;
10
- export declare function updateApiConnection(config: StreamByConfig, projectId: string, connectionId: string, data: {
11
- name?: string;
12
- apiUrl?: string;
13
- method?: ApiConnectionMethod;
14
- prefix?: string;
15
- description?: string;
16
- credentialId?: string;
17
- }): Promise<ApiConnection>;
18
- export declare function deleteApiConnection(config: StreamByConfig, projectId: string, connectionId: string): Promise<void>;
@@ -1,65 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.addApiConnection = addApiConnection;
4
- exports.updateApiConnection = updateApiConnection;
5
- exports.deleteApiConnection = deleteApiConnection;
6
- const mongodb_1 = require("mongodb");
7
- const manager_1 = require("../models/manager");
8
- async function addApiConnection(config, projectId, data) {
9
- const ProjectModel = (0, manager_1.getModel)('projects');
10
- const project = await ProjectModel.findOne({ _id: projectId });
11
- if (!project) {
12
- throw new Error('Project not found.');
13
- }
14
- const connection = {
15
- id: new mongodb_1.ObjectId().toHexString(),
16
- name: data.name,
17
- prefix: data.prefix,
18
- apiUrl: data.apiUrl,
19
- method: data.method,
20
- projectId,
21
- createdAt: new Date(),
22
- ...(data.description !== undefined && { description: data.description }),
23
- ...(data.credentialId !== undefined && { credentialId: data.credentialId }),
24
- };
25
- const updatedProject = await ProjectModel.update({ _id: projectId }, { $push: { apiConnections: connection } });
26
- if (!updatedProject) {
27
- throw new Error('Failed to add API connection to project.');
28
- }
29
- return connection;
30
- }
31
- async function updateApiConnection(config, projectId, connectionId, data) {
32
- const ProjectModel = (0, manager_1.getModel)('projects');
33
- const project = await ProjectModel.findOne({ _id: projectId });
34
- if (!project)
35
- throw new Error('Project not found.');
36
- const connections = project.apiConnections ?? [];
37
- const index = connections.findIndex((c) => c.id === connectionId);
38
- if (index === -1)
39
- throw new Error('API connection not found.');
40
- const updated = {
41
- ...connections[index],
42
- ...(data.name !== undefined && { name: data.name }),
43
- ...(data.apiUrl !== undefined && { apiUrl: data.apiUrl }),
44
- ...(data.method !== undefined && { method: data.method }),
45
- ...(data.prefix !== undefined && { prefix: data.prefix }),
46
- ...(data.description !== undefined && { description: data.description }),
47
- ...(data.credentialId !== undefined && { credentialId: data.credentialId }),
48
- };
49
- connections[index] = updated;
50
- const result = await ProjectModel.update({ _id: projectId }, { $set: { apiConnections: connections } });
51
- if (!result)
52
- throw new Error('Failed to update API connection.');
53
- return updated;
54
- }
55
- async function deleteApiConnection(config, projectId, connectionId) {
56
- const ProjectModel = (0, manager_1.getModel)('projects');
57
- const project = await ProjectModel.findOne({ _id: projectId });
58
- if (!project) {
59
- throw new Error('Project not found.');
60
- }
61
- const updatedProject = await ProjectModel.update({ _id: projectId }, { $pull: { apiConnections: { id: connectionId } } });
62
- if (!updatedProject) {
63
- throw new Error('Failed to delete API connection from project.');
64
- }
65
- }
@@ -1,8 +0,0 @@
1
- import { StreamByConfig, Credential, ProjectInfo } from '../types';
2
- export declare function addCredential(config: StreamByConfig, projectId: string, newCredential: Omit<Credential, 'encryptedValue'> & {
3
- value: string;
4
- }): Promise<ProjectInfo>;
5
- export declare function updateCredential(config: StreamByConfig, projectId: string, credentialId: string, updates: Partial<Omit<Credential, 'encryptedValue'> & {
6
- value: string;
7
- }>): Promise<ProjectInfo>;
8
- export declare function deleteCredential(config: StreamByConfig, projectId: string, credentialId: string): Promise<ProjectInfo>;
@@ -1,70 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.addCredential = addCredential;
4
- exports.updateCredential = updateCredential;
5
- exports.deleteCredential = deleteCredential;
6
- const manager_1 = require("../models/manager");
7
- const encryption_1 = require("../utils/encryption");
8
- const mongodb_1 = require("mongodb");
9
- async function addCredential(config, projectId, newCredential) {
10
- if (!(0, encryption_1.isEncryptionKeySet)()) {
11
- throw new Error('Encryption key is not set. Cannot add credentials.');
12
- }
13
- const ProjectModel = (0, manager_1.getModel)('projects');
14
- const project = await ProjectModel.findOne({ _id: projectId });
15
- if (!project) {
16
- throw new Error('Project not found.');
17
- }
18
- const encryptedValue = (0, encryption_1.encrypt)(newCredential.value);
19
- const credentialToSave = {
20
- id: newCredential.id || new mongodb_1.ObjectId().toHexString(), // Generate ID if not provided
21
- key: newCredential.key,
22
- encryptedValue: encryptedValue,
23
- };
24
- const updatedProject = await ProjectModel.update({ _id: projectId }, { $push: { credentials: credentialToSave } });
25
- if (!updatedProject) {
26
- throw new Error('Failed to add credential to project.');
27
- }
28
- return updatedProject;
29
- }
30
- async function updateCredential(config, projectId, credentialId, updates) {
31
- if (!(0, encryption_1.isEncryptionKeySet)()) {
32
- throw new Error('Encryption key is not set. Cannot update credentials.');
33
- }
34
- const ProjectModel = (0, manager_1.getModel)('projects');
35
- const project = await ProjectModel.findOne({ _id: projectId });
36
- if (!project) {
37
- throw new Error('Project not found.');
38
- }
39
- const credentialIndex = project.credentials?.findIndex(cred => cred.id === credentialId);
40
- if (credentialIndex === undefined || credentialIndex === -1) {
41
- throw new Error(`Credential with ID ${credentialId} not found.`);
42
- }
43
- const currentCredential = project.credentials[credentialIndex];
44
- let encryptedValue = currentCredential.encryptedValue;
45
- if (updates.value !== undefined) {
46
- encryptedValue = (0, encryption_1.encrypt)(updates.value);
47
- }
48
- const updatedCredential = {
49
- ...currentCredential,
50
- key: updates.key || currentCredential.key,
51
- encryptedValue: encryptedValue,
52
- };
53
- const updatedProject = await ProjectModel.update({ _id: projectId, 'credentials.id': credentialId }, { $set: { 'credentials.$': updatedCredential } });
54
- if (!updatedProject) {
55
- throw new Error('Failed to update credential in project.');
56
- }
57
- return updatedProject;
58
- }
59
- async function deleteCredential(config, projectId, credentialId) {
60
- const ProjectModel = (0, manager_1.getModel)('projects');
61
- const project = await ProjectModel.findOne({ _id: projectId });
62
- if (!project) {
63
- throw new Error('Project not found.');
64
- }
65
- const updatedProject = await ProjectModel.update({ _id: projectId }, { $pull: { credentials: { id: credentialId } } });
66
- if (!updatedProject) {
67
- throw new Error('Failed to delete credential from project.');
68
- }
69
- return updatedProject;
70
- }
@@ -1,2 +0,0 @@
1
- import { NodeSchema, StreamByConfig } from '../types';
2
- export declare function executePipeline(nodeSchema: NodeSchema, project: any, config: StreamByConfig): Promise<any>;
@@ -1,292 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.executePipeline = executePipeline;
4
- const connectionManager_1 = require("../adapters/database/connectionManager");
5
- const encryption_1 = require("../utils/encryption");
6
- const dbConnection_1 = require("./dbConnection");
7
- const jobQueue_1 = require("./jobQueue");
8
- const mediaProcessor_1 = require("./mediaProcessor");
9
- const vfxProcessor_1 = require("./vfxProcessor");
10
- const aiProcessor_1 = require("./aiProcessor");
11
- const storage_1 = require("../providers/storage");
12
- function applyFilterConfig(payload, config) {
13
- const isArr = Array.isArray(payload);
14
- let r = isArr ? [...payload] : payload;
15
- if (config.conditions?.length) {
16
- const matches = (item) => config.conditions.every(c => {
17
- const v = item?.[c.field];
18
- switch (c.op) {
19
- case 'eq': return String(v) === c.value;
20
- case 'neq': return String(v) !== c.value;
21
- case 'gt': return Number(v) > Number(c.value);
22
- case 'lt': return Number(v) < Number(c.value);
23
- case 'gte': return Number(v) >= Number(c.value);
24
- case 'lte': return Number(v) <= Number(c.value);
25
- case 'contains': return String(v).includes(c.value);
26
- case 'startsWith': return String(v).startsWith(c.value);
27
- case 'endsWith': return String(v).endsWith(c.value);
28
- default: return true;
29
- }
30
- });
31
- r = isArr ? r.filter(matches) : (matches(r) ? r : null);
32
- if (r === null)
33
- return null;
34
- }
35
- if (config.includeFields?.length) {
36
- const pick = (item) => {
37
- if (!item || typeof item !== 'object')
38
- return item;
39
- const o = {};
40
- for (const f of config.includeFields)
41
- if (f in item)
42
- o[f] = item[f];
43
- return o;
44
- };
45
- r = isArr ? r.map(pick) : pick(r);
46
- }
47
- if (config.renameFields?.length) {
48
- const ren = (item) => {
49
- if (!item || typeof item !== 'object')
50
- return item;
51
- const o = { ...item };
52
- for (const { from, to } of config.renameFields) {
53
- if (from in o) {
54
- o[to] = o[from];
55
- delete o[from];
56
- }
57
- }
58
- return o;
59
- };
60
- r = isArr ? r.map(ren) : ren(r);
61
- }
62
- if (config.limit && isArr)
63
- r = r.slice(0, config.limit);
64
- if (config.wrapKey)
65
- r = { [config.wrapKey]: r };
66
- return r;
67
- }
68
- function getSources(nodes, edges, targetId, targetHandle) {
69
- return edges
70
- .filter(e => e.target === targetId && e.targetHandle === targetHandle)
71
- .map(e => nodes.find(n => n.id === e.source))
72
- .filter((n) => n !== undefined);
73
- }
74
- function getTarget(nodes, edges, sourceId, sourceHandle) {
75
- const edge = edges.find(e => e.source === sourceId && e.sourceHandle === sourceHandle);
76
- return edge ? (nodes.find(n => n.id === edge.target) ?? null) : null;
77
- }
78
- async function executePipeline(nodeSchema, project, config) {
79
- const nodes = nodeSchema.nodes;
80
- const edges = nodeSchema.edges;
81
- // 1. Data layer — nodes connected to streamby in-bottom
82
- const dataSources = getSources(nodes, edges, 'streamby', 'in-bottom');
83
- const dataResults = [];
84
- for (const node of dataSources) {
85
- if (node.type === 'jsonInputNode') {
86
- try {
87
- dataResults.push(JSON.parse(node.data?.jsonString || 'null'));
88
- }
89
- catch {
90
- dataResults.push(null);
91
- }
92
- }
93
- else if (node.type === 'dataSourceNode') {
94
- const tableName = (node.data?.tableName || node.data?.subtitle || node.data?.label);
95
- if (!tableName)
96
- continue;
97
- const connectionId = node.data?.connectionId;
98
- const recordId = node.data?.recordId;
99
- const projectIdentifier = project._id?.toString() ?? project.id;
100
- const fetchData = async (client, type) => recordId
101
- ? (0, dbConnection_1.queryRecordByIdInternal)(client, type, tableName, recordId, projectIdentifier)
102
- : (0, dbConnection_1.queryRecordsInternal)(client, type, tableName, 500, 0, projectIdentifier);
103
- if (connectionId) {
104
- const { client, type } = (0, connectionManager_1.getConnection)(connectionId);
105
- dataResults.push(await fetchData(client, type));
106
- }
107
- else {
108
- // legacy fallback for nodes saved before connectionId was introduced
109
- const targetDb = config.databases?.find((db) => db.type === project.dbType && db.main)
110
- ?? config.databases?.find((db) => db.type === project.dbType);
111
- if (!targetDb)
112
- throw new Error(`No database connection for type ${project.dbType}`);
113
- const { client, type } = (0, connectionManager_1.getConnection)(targetDb.id);
114
- dataResults.push(await fetchData(client, type));
115
- }
116
- }
117
- else if (node.type === 'apiConnectionNode') {
118
- const apiConnection = project.apiConnections?.find((c) => c.id === node.data?.connectionId);
119
- if (!apiConnection)
120
- continue;
121
- const headers = { 'Content-Type': 'application/json' };
122
- if (apiConnection.credentialId && (0, encryption_1.isEncryptionKeySet)()) {
123
- const credential = project.credentials?.find((c) => c.id === apiConnection.credentialId);
124
- if (credential) {
125
- const decrypted = (0, encryption_1.decrypt)(credential.encryptedValue);
126
- const prefix = apiConnection.prefix ? `${apiConnection.prefix} ` : '';
127
- headers['Authorization'] = `${prefix}${decrypted}`;
128
- }
129
- }
130
- const response = await fetch(apiConnection.apiUrl, { method: apiConnection.method || 'GET', headers });
131
- if (!response.ok)
132
- throw new Error(`API connection fetch failed: ${response.statusText}`);
133
- dataResults.push(await response.json());
134
- }
135
- }
136
- let payload = dataResults.length === 1 ? dataResults[0] : dataResults;
137
- // 2. Process layer — chain from streamby out-top → processNode in-process → out-process → ...
138
- const adapter = (0, storage_1.createStorageProvider)(config.storageProviders);
139
- const projectId = project._id?.toString() ?? project.id;
140
- // userId is not available in pipeline context; use a sentinel for job attribution
141
- const systemUserId = 'pipeline';
142
- let processNode = getTarget(nodes, edges, 'streamby', 'out-top');
143
- while (processNode) {
144
- const nodeData = processNode.data ?? {};
145
- const fileId = nodeData.fileId;
146
- if (processNode.type === 'transcodeNode' && fileId) {
147
- const job = (0, jobQueue_1.createJob)('transcode', systemUserId, projectId, nodeData);
148
- setImmediate(() => (0, mediaProcessor_1.runTranscodeJob)(job.jobId, fileId, projectId, {
149
- codec: nodeData.codec,
150
- resolution: nodeData.resolution,
151
- outputFormat: nodeData.outputFormat,
152
- bitrate: nodeData.bitrate,
153
- audioCodec: nodeData.audioCodec,
154
- }, adapter));
155
- payload = { ...payload, jobId: job.jobId, jobType: 'transcode' };
156
- }
157
- else if (processNode.type === 'captionNode' && fileId) {
158
- const job = (0, jobQueue_1.createJob)('caption', systemUserId, projectId, nodeData);
159
- setImmediate(() => (0, mediaProcessor_1.runCaptionJob)(job.jobId, fileId, projectId, {
160
- sourceLanguage: nodeData.sourceLanguage,
161
- outputFormat: nodeData.outputFormat,
162
- provider: nodeData.provider,
163
- }));
164
- payload = { ...payload, jobId: job.jobId, jobType: 'caption' };
165
- }
166
- else if (processNode.type === 'thumbnailNode' && fileId) {
167
- const job = (0, jobQueue_1.createJob)('thumbnail', systemUserId, projectId, nodeData);
168
- setImmediate(() => (0, mediaProcessor_1.runThumbnailJob)(job.jobId, fileId, projectId, {
169
- timecode: nodeData.timecode,
170
- resolution: nodeData.resolution,
171
- strategy: nodeData.strategy,
172
- }));
173
- payload = { ...payload, jobId: job.jobId, jobType: 'thumbnail' };
174
- }
175
- else if (processNode.type === 'ingestNode' && fileId) {
176
- const job = (0, jobQueue_1.createJob)('ingest', systemUserId, projectId, nodeData);
177
- setImmediate(() => (0, mediaProcessor_1.runIngestJob)(job.jobId, fileId, projectId));
178
- payload = { ...payload, jobId: job.jobId, jobType: 'ingest' };
179
- }
180
- else if (processNode.type === 'renderJobNode' && fileId) {
181
- const job = (0, jobQueue_1.createJob)('render', systemUserId, projectId, nodeData);
182
- setImmediate(() => (0, vfxProcessor_1.runRenderJob)(job.jobId, fileId, projectId, {
183
- renderer: nodeData.renderer,
184
- renderFarmConnectionId: nodeData.renderFarmConnectionId,
185
- frameRange: nodeData.frameRange,
186
- resolution: nodeData.resolution,
187
- samples: nodeData.samples,
188
- outputFormat: nodeData.outputFormat,
189
- }));
190
- payload = { ...payload, jobId: job.jobId, jobType: 'render' };
191
- }
192
- else if (processNode.type === 'formatConvertNode' && fileId) {
193
- const job = (0, jobQueue_1.createJob)('format-convert', systemUserId, projectId, nodeData);
194
- setImmediate(() => (0, vfxProcessor_1.runFormatConvertJob)(job.jobId, fileId, projectId, {
195
- inputFormat: nodeData.inputFormat,
196
- outputFormat: nodeData.outputFormat,
197
- applyTransforms: nodeData.applyTransforms,
198
- embedTextures: nodeData.embedTextures,
199
- }));
200
- payload = { ...payload, jobId: job.jobId, jobType: 'format-convert' };
201
- }
202
- else if (processNode.type === 'lodNode' && fileId) {
203
- const job = (0, jobQueue_1.createJob)('lod', systemUserId, projectId, nodeData);
204
- setImmediate(() => (0, vfxProcessor_1.runLodJob)(job.jobId, fileId, projectId, {
205
- levels: nodeData.levels,
206
- reductionRatios: nodeData.reductionRatios,
207
- algorithm: nodeData.algorithm,
208
- outputFormat: nodeData.outputFormat,
209
- }));
210
- payload = { ...payload, jobId: job.jobId, jobType: 'lod' };
211
- }
212
- else if (processNode.type === 'qcCheckNode' && fileId) {
213
- const checks = nodeData.checks ?? [];
214
- const checkResults = checks.map((name) => ({
215
- name, passed: true, value: 'ok', threshold: 'ok',
216
- }));
217
- payload = { ...payload, qcReport: { checks: checkResults, overallPassed: true } };
218
- }
219
- else if (processNode.type === 'transcriptionNode' && fileId) {
220
- const job = (0, jobQueue_1.createJob)('transcription', systemUserId, projectId, nodeData);
221
- setImmediate(() => (0, aiProcessor_1.runTranscriptionJob)(job.jobId, fileId, projectId, {
222
- model: nodeData.model,
223
- sourceLanguage: nodeData.sourceLanguage,
224
- outputFormats: nodeData.outputFormats,
225
- provider: nodeData.provider,
226
- credentialId: nodeData.credentialId,
227
- }));
228
- payload = { ...payload, jobId: job.jobId, jobType: 'transcription' };
229
- }
230
- else if (processNode.type === 'upscaleNode' && fileId) {
231
- const job = (0, jobQueue_1.createJob)('upscale', systemUserId, projectId, nodeData);
232
- setImmediate(() => (0, aiProcessor_1.runUpscaleJob)(job.jobId, fileId, projectId, {
233
- scale: nodeData.scale,
234
- model: nodeData.model,
235
- mode: nodeData.mode,
236
- credentialId: nodeData.credentialId,
237
- }));
238
- payload = { ...payload, jobId: job.jobId, jobType: 'upscale' };
239
- }
240
- else if (processNode.type === 'proceduralAssetNode') {
241
- const job = (0, jobQueue_1.createJob)('generate-asset', systemUserId, projectId, nodeData);
242
- setImmediate(() => (0, aiProcessor_1.runGenerateAssetJob)(job.jobId, projectId, {
243
- assetType: nodeData.assetType,
244
- provider: nodeData.provider,
245
- prompt: nodeData.prompt ?? '',
246
- seed: nodeData.seed,
247
- credentialId: nodeData.credentialId,
248
- }));
249
- payload = { ...payload, jobId: job.jobId, jobType: 'generate-asset' };
250
- }
251
- else if (processNode.type === 'pipelineSuggestNode') {
252
- const suggestion = await (0, aiProcessor_1.buildPipelineSuggestion)({ nodes, edges }, Object.keys(nodeSchema));
253
- payload = { ...payload, pipelineSuggestion: suggestion };
254
- }
255
- processNode = getTarget(nodes, edges, processNode.id, 'out-process');
256
- }
257
- // 3. Filter + output lane — streamby out-right → filterNode|annotationNode|deliverableNode|distributionNode
258
- const outputLaneTypes = new Set(['filterNode', 'annotationNode', 'deliverableNode', 'distributionNode']);
259
- let outputNode = getTarget(nodes, edges, 'streamby', 'out-right');
260
- while (outputNode) {
261
- if (outputNode.type === 'filterNode') {
262
- const cfg = outputNode.data?.filterConfig;
263
- if (cfg)
264
- payload = applyFilterConfig(payload, cfg);
265
- }
266
- else if (outputNode.type === 'deliverableNode') {
267
- payload = {
268
- ...payload,
269
- deliverable: {
270
- type: outputNode.data?.deliverableType ?? 'asset-bundle',
271
- version: outputNode.data?.deliverableVersion ?? '1.0.0',
272
- },
273
- };
274
- }
275
- else if (outputNode.type === 'distributionNode') {
276
- // Distribution is async — the actual publish is handled by the host worker
277
- payload = {
278
- ...payload,
279
- distribution: {
280
- target: outputNode.data?.distributionTarget,
281
- connectionId: outputNode.data?.distributionConnectionId,
282
- channel: outputNode.data?.channel,
283
- status: 'queued',
284
- },
285
- };
286
- }
287
- // annotationNode — pass-through; annotations are stored separately via the review API
288
- const next = getTarget(nodes, edges, outputNode.id, 'out-filter');
289
- outputNode = next && outputLaneTypes.has(next.type) ? next : null;
290
- }
291
- return payload;
292
- }