streamby-core 0.9.21 → 0.10.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/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
- export { initProjectModel } from './db/initProjectModel';
2
- export { createStreamByRouter } from './middleware/createRouter';
3
- export { createMongoProjectProvider } from './providers/mongoProjectProvider';
1
+ import { StreamByConfig, StorageAdapter } from './types';
2
+ export declare function createStreamByApp(config: StreamByConfig & {
3
+ adapter?: StorageAdapter;
4
+ }): import("express-serve-static-core").Express;
package/dist/index.js CHANGED
@@ -1,9 +1,14 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createMongoProjectProvider = exports.createStreamByRouter = exports.initProjectModel = void 0;
4
- var initProjectModel_1 = require("./db/initProjectModel");
5
- Object.defineProperty(exports, "initProjectModel", { enumerable: true, get: function () { return initProjectModel_1.initProjectModel; } });
6
- var createRouter_1 = require("./middleware/createRouter");
7
- Object.defineProperty(exports, "createStreamByRouter", { enumerable: true, get: function () { return createRouter_1.createStreamByRouter; } });
8
- var mongoProjectProvider_1 = require("./providers/mongoProjectProvider");
9
- Object.defineProperty(exports, "createMongoProjectProvider", { enumerable: true, get: function () { return mongoProjectProvider_1.createMongoProjectProvider; } });
6
+ exports.createStreamByApp = createStreamByApp;
7
+ const express_1 = __importDefault(require("express"));
8
+ const createRouter_1 = require("./middleware/createRouter");
9
+ function createStreamByApp(config) {
10
+ const app = (0, express_1.default)();
11
+ app.use(express_1.default.json());
12
+ app.use((0, createRouter_1.createStreamByRouter)(config));
13
+ return app;
14
+ }
@@ -1,2 +1,5 @@
1
- import type { StreamByConfig } from '../types';
2
- export declare function createStreamByRouter(config: StreamByConfig): import("express-serve-static-core").Router;
1
+ import { Router } from 'express';
2
+ import { StreamByConfig, StorageAdapter } from '../types';
3
+ export declare function createStreamByRouter(config: StreamByConfig & {
4
+ adapter?: StorageAdapter;
5
+ }): Router;
@@ -5,23 +5,174 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.createStreamByRouter = createStreamByRouter;
7
7
  const express_1 = __importDefault(require("express"));
8
+ const s3_1 = require("../adapters/s3");
9
+ const file_1 = require("../services/file");
8
10
  const project_1 = require("../services/project");
11
+ const presign_1 = require("../services/presign");
12
+ function isProjectMember(project, userId) {
13
+ return project.members?.some((m) => m.userId?.toString() === userId?.toString());
14
+ }
9
15
  function createStreamByRouter(config) {
10
- const app = express_1.default.Router();
11
- app.post('/project', (req, res) => {
12
- (0, project_1.createProjectService)(req, config.authProvider, config.projectProvider)
13
- .then((result) => res.json(result))
14
- .catch((err) => res.status(400).json({ error: err.message }));
15
- });
16
- app.put('/project/:projectId', (req, res) => {
17
- (0, project_1.updateProjectService)(req, config.authProvider, config.projectProvider)
18
- .then((result) => res.json(result))
19
- .catch((err) => res.status(400).json({ error: err.message }));
20
- });
21
- app.delete('/project/:projectId/image', (req, res) => {
22
- (0, project_1.deleteProjectImageService)(req, config.authProvider, config.projectProvider, config.storageAdapter)
23
- .then((result) => res.json(result))
24
- .catch((err) => res.status(400).json({ error: err.message }));
25
- });
26
- return app;
16
+ const router = express_1.default.Router();
17
+ const adapter = config.adapter || (() => {
18
+ switch (config.storageProvider.type) {
19
+ case 's3':
20
+ return (0, s3_1.createS3Adapter)(config.storageProvider.config);
21
+ default:
22
+ throw new Error('Unsupported storage type');
23
+ }
24
+ })();
25
+ router.get('/auth', async (req, res) => {
26
+ try {
27
+ const auth = await config.authProvider(req);
28
+ res.status(200).json({ logged: true, ...auth });
29
+ }
30
+ catch (err) {
31
+ res.status(401).json({ logged: false });
32
+ }
33
+ });
34
+ router.get('/upload-project-image-url/:id', async (req, res) => {
35
+ try {
36
+ const auth = await config.authProvider(req);
37
+ if (auth.role !== 'admin' && auth.role !== 'editor') {
38
+ return res.status(403).json({ error: 'Permission denied' });
39
+ }
40
+ const projectId = req.params.id;
41
+ if (!projectId) {
42
+ return res.status(400).json({ error: 'Missing projectId' });
43
+ }
44
+ const url = await (0, presign_1.getPresignedProjectImageUrl)(adapter, projectId);
45
+ res.json(url);
46
+ }
47
+ catch (err) {
48
+ res.status(500).json({ error: 'Failed to generate presigned URL', details: err.message });
49
+ }
50
+ });
51
+ router.delete('/delete-project-image-url/:id', async (req, res) => {
52
+ try {
53
+ const auth = await config.authProvider(req);
54
+ if (auth.role !== 'admin' && auth.role !== 'editor') {
55
+ return res.status(403).json({ error: 'Permission denied' });
56
+ }
57
+ const projectId = req.params.id;
58
+ if (!projectId) {
59
+ return res.status(400).json({ error: 'Missing projectId' });
60
+ }
61
+ await (0, file_1.deleteProjectImage)(adapter, projectId);
62
+ const updated = await (0, project_1.deleteProjectImageService)(req, config.authProvider, config.projectProvider);
63
+ res.status(201).json(updated);
64
+ }
65
+ catch (err) {
66
+ res.status(500).json({ error: 'Failed to delete image', details: err.message });
67
+ }
68
+ });
69
+ router.post('/upload-url', async (req, res) => {
70
+ try {
71
+ const auth = await config.authProvider(req);
72
+ if (auth.role !== 'admin' && auth.role !== 'editor') {
73
+ return res.status(403).json({ error: 'Permission denied' });
74
+ }
75
+ const { filename, contentType, projectId } = req.body;
76
+ if (!filename || !contentType || !projectId) {
77
+ return res.status(400).json({ error: 'Missing filename, contentType, or projectId' });
78
+ }
79
+ const url = await (0, presign_1.getPresignedUrl)(adapter, contentType, projectId);
80
+ res.json(url);
81
+ }
82
+ catch (err) {
83
+ res.status(500).json({ error: 'Failed to generate upload URL', details: err.message });
84
+ }
85
+ });
86
+ router.get('/files', async (req, res) => {
87
+ try {
88
+ const auth = await config.authProvider(req);
89
+ const projectId = (req.query.projectId || req.headers['x-project-id']);
90
+ if (!projectId || !auth.projects.includes(projectId)) {
91
+ return res.status(403).json({ error: 'Unauthorized or missing projectId' });
92
+ }
93
+ const files = await (0, file_1.listFilesService)(adapter, req, projectId);
94
+ res.json(files);
95
+ }
96
+ catch (err) {
97
+ res.status(500).json({ error: 'Failed to list files', details: err });
98
+ }
99
+ });
100
+ router.patch('/projects/:id', async (req, res) => {
101
+ try {
102
+ const auth = await config.authProvider(req);
103
+ if (auth.role !== 'admin' && auth.role !== 'editor') {
104
+ return res.status(403).json({ error: 'Permission denied' });
105
+ }
106
+ const projectId = req.params.id;
107
+ const updates = req.body;
108
+ if (!updates || typeof updates !== 'object') {
109
+ return res.status(400).json({ error: 'Missing updates payload' });
110
+ }
111
+ const updated = await config.projectProvider.update(projectId, updates);
112
+ res.status(200).json({ success: true, project: updated });
113
+ }
114
+ catch (err) {
115
+ res.status(500).json({ error: 'Failed to update project', details: err.message });
116
+ }
117
+ });
118
+ router.get('/projects/:id', async (req, res) => {
119
+ try {
120
+ const auth = await config.authProvider(req);
121
+ const projectId = req.params.id;
122
+ const project = await config.projectProvider.getById(projectId);
123
+ if (!project) {
124
+ return res.status(404).json({ error: 'Project not found' });
125
+ }
126
+ if (!isProjectMember(project, auth.userId)) {
127
+ return res.status(403).json({ error: 'Unauthorized project access' });
128
+ }
129
+ res.json({ project });
130
+ }
131
+ catch (err) {
132
+ res.status(500).json({ error: 'Failed to fetch project', details: err.message });
133
+ }
134
+ });
135
+ router.post('/projects/create', async (req, res) => {
136
+ try {
137
+ const auth = await config.authProvider(req);
138
+ if (auth.role !== 'admin' && auth.role !== 'editor') {
139
+ return res.status(403).json({ error: 'Permission denied' });
140
+ }
141
+ const created = await (0, project_1.createProjectService)(req, config.authProvider, config.projectProvider);
142
+ res.status(201).json(created);
143
+ }
144
+ catch (err) {
145
+ res.status(500).json({ error: 'Failed to create project', details: err.message });
146
+ }
147
+ });
148
+ router.delete('/projects/:id', async (req, res) => {
149
+ try {
150
+ const auth = await config.authProvider(req);
151
+ const projectId = req.params.id;
152
+ const project = await config.projectProvider.getById(projectId);
153
+ if (!project) {
154
+ return res.status(404).json({ error: 'Project not found' });
155
+ }
156
+ if (!isProjectMember(project, auth.userId)) {
157
+ return res.status(403).json({ error: 'Unauthorized project access' });
158
+ }
159
+ await config.projectProvider.delete(projectId);
160
+ await adapter.deleteProjectDirectory(projectId);
161
+ res.status(200).json({ success: true });
162
+ }
163
+ catch (err) {
164
+ res.status(500).json({ error: 'Failed to delete project', details: err.message });
165
+ }
166
+ });
167
+ router.get('/projects', async (req, res) => {
168
+ try {
169
+ const auth = await config.authProvider(req);
170
+ const projects = await config.projectProvider.list(auth.userId);
171
+ res.json({ projects });
172
+ }
173
+ catch (err) {
174
+ res.status(500).json({ error: 'Failed to list projects', details: err });
175
+ }
176
+ });
177
+ return router;
27
178
  }
@@ -2,3 +2,4 @@ import { Request } from 'express';
2
2
  import { StreamByConfig, AuthContext } from '../types';
3
3
  export declare function resolveAuth(config: StreamByConfig, req: Request): Promise<AuthContext>;
4
4
  export declare function checkRole(auth: AuthContext, required: 'viewer' | 'editor' | 'admin'): void;
5
+ export declare function dummyAuthProvider(req: Request): Promise<AuthContext>;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.resolveAuth = resolveAuth;
4
4
  exports.checkRole = checkRole;
5
+ exports.dummyAuthProvider = dummyAuthProvider;
5
6
  async function resolveAuth(config, req) {
6
7
  const auth = await config.authProvider(req);
7
8
  if (!auth ||
@@ -21,3 +22,11 @@ function checkRole(auth, required) {
21
22
  throw new Error(`Insufficient role: requires ${required}, found ${auth.role}`);
22
23
  }
23
24
  }
25
+ async function dummyAuthProvider(req) {
26
+ return {
27
+ userId: '67ad0832cae5e7e270ee086a',
28
+ username: 'dev-user',
29
+ projects: [],
30
+ role: 'admin'
31
+ };
32
+ }
@@ -1,5 +1,5 @@
1
1
  import { Request } from 'express';
2
- import { AuthProvider, ProjectProvider, StorageAdapter } from '../types';
2
+ import { AuthProvider, ProjectProvider } from '../types';
3
3
  export declare function createProjectService(req: Request, authProvider: AuthProvider, projectProvider: ProjectProvider): Promise<{
4
4
  success: boolean;
5
5
  project: import("../types").ProjectInfo;
@@ -8,6 +8,6 @@ export declare function updateProjectService(req: Request, authProvider: AuthPro
8
8
  success: boolean;
9
9
  project: import("../types").ProjectInfo;
10
10
  }>;
11
- export declare function deleteProjectImageService(req: Request, authProvider: AuthProvider, projectProvider: ProjectProvider, storageAdapter: StorageAdapter): Promise<{
11
+ export declare function deleteProjectImageService(req: Request, authProvider: AuthProvider, projectProvider: ProjectProvider): Promise<{
12
12
  success: boolean;
13
13
  }>;
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createProjectService = createProjectService;
4
4
  exports.updateProjectService = updateProjectService;
5
5
  exports.deleteProjectImageService = deleteProjectImageService;
6
- const file_1 = require("./file");
7
6
  async function createProjectService(req, authProvider, projectProvider) {
8
7
  const { name, description } = req.body;
9
8
  const auth = await authProvider(req);
@@ -37,7 +36,7 @@ async function updateProjectService(req, authProvider, projectProvider) {
37
36
  project: updatedProject,
38
37
  };
39
38
  }
40
- async function deleteProjectImageService(req, authProvider, projectProvider, storageAdapter) {
39
+ async function deleteProjectImageService(req, authProvider, projectProvider) {
41
40
  const { projectId } = req.params;
42
41
  const auth = await authProvider(req);
43
42
  const project = await projectProvider.getById(projectId);
@@ -47,6 +46,8 @@ async function deleteProjectImageService(req, authProvider, projectProvider, sto
47
46
  if (!project.members?.find((e) => e.userId === auth.userId)) {
48
47
  throw new Error('Unauthorized');
49
48
  }
50
- await (0, file_1.deleteProjectImage)(storageAdapter, projectId);
51
- return { success: true };
49
+ await projectProvider.update(projectId, { image: '' });
50
+ return {
51
+ success: true,
52
+ };
52
53
  }
@@ -40,7 +40,6 @@ export interface StreamByConfig {
40
40
  config: S3Config;
41
41
  };
42
42
  authProvider: AuthProvider;
43
- storageAdapter: StorageAdapter;
44
43
  projectProvider: ProjectProvider;
45
44
  dbConnection?: Connection;
46
45
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "streamby-core",
3
- "version": "0.9.21",
3
+ "version": "0.10.00",
4
4
  "description": "StreamBy middleware framework for media storage management",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -10,7 +10,7 @@
10
10
  "scripts": {
11
11
  "build": "tsc",
12
12
  "test": "vitest",
13
- "dev": "tsc --watch",
13
+ "dev": "ts-node-dev --respawn --clear dev.ts",
14
14
  "prepublishOnly": "npm run build"
15
15
  },
16
16
  "repository": {
@@ -32,14 +32,17 @@
32
32
  "@aws-sdk/client-s3": "^3.528.0",
33
33
  "@aws-sdk/s3-request-presigner": "^3.787.0",
34
34
  "bcrypt": "^5.1.1",
35
+ "dotenv": "^16.5.0",
35
36
  "express": "^4.0.0",
36
37
  "mongoose": "^8.13.2"
37
38
  },
38
39
  "devDependencies": {
39
40
  "@types/bcrypt": "^5.0.2",
40
41
  "@types/express": "^4.17.17",
42
+ "@types/node": "^22.15.21",
41
43
  "@types/supertest": "^6.0.3",
42
44
  "supertest": "^7.1.0",
45
+ "ts-node-dev": "^2.0.0",
43
46
  "typescript": "^5.8.3",
44
47
  "vitest": "^3.1.1"
45
48
  },