streamby-core 0.7.2 โ 0.8.1
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/README.md +114 -114
- package/dist/adapters/s3.js +5 -17
- package/dist/middleware/createRouter.js +12 -26
- package/dist/services/file.d.ts +0 -1
- package/dist/services/file.js +0 -4
- package/dist/services/presign.d.ts +1 -1
- package/dist/services/presign.js +2 -2
- package/dist/types/index.d.ts +2 -3
- package/package.json +46 -46
package/README.md
CHANGED
|
@@ -1,114 +1,114 @@
|
|
|
1
|
-
# @streamby/core
|
|
2
|
-
|
|
3
|
-
Middleware framework for building storage-agnostic media APIs.
|
|
4
|
-
Part of the [StreamBy](https://streamby.nhexa.cl) ecosystem by TerminalCore Labs.
|
|
5
|
-
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## ๐ What is it?
|
|
9
|
-
|
|
10
|
-
`@streamby/core` is a plug-and-play middleware for Express (or compatible frameworks) that enables file uploads, listings and **multi-project access** over services like:
|
|
11
|
-
|
|
12
|
-
- โ
AWS S3
|
|
13
|
-
- โ
Google Cloud Storage (soon)
|
|
14
|
-
- โ
Cloudflare R2 (soon)
|
|
15
|
-
- โ
Local/Personal servers (soon)
|
|
16
|
-
|
|
17
|
-
It's designed to be installed inside your existing API as a library โ **no need to run a separate backend**.
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## ๐ฆ Installation
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
npm install @streamby/core
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
## ๐งฑ Basic usage
|
|
30
|
-
|
|
31
|
-
```ts
|
|
32
|
-
import express from 'express';
|
|
33
|
-
import { createStreamByRouter } from '@streamby/core';
|
|
34
|
-
|
|
35
|
-
const app = express();
|
|
36
|
-
|
|
37
|
-
app.use('/streamby', createStreamByRouter({
|
|
38
|
-
storageProvider: {
|
|
39
|
-
type: 's3',
|
|
40
|
-
config: {
|
|
41
|
-
bucket: 'your-bucket-name',
|
|
42
|
-
region: 'your-region',
|
|
43
|
-
accessKeyId: 'YOUR_AWS_KEY',
|
|
44
|
-
secretAccessKey: 'YOUR_AWS_SECRET'
|
|
45
|
-
}
|
|
46
|
-
},
|
|
47
|
-
authProvider: async (req) => {
|
|
48
|
-
// extract token/cookie and validate
|
|
49
|
-
return {
|
|
50
|
-
userId: 'demo',
|
|
51
|
-
projects: ['demo-project'],
|
|
52
|
-
role: 'admin',
|
|
53
|
-
};
|
|
54
|
-
},
|
|
55
|
-
projectProvider: async (projectId) => {
|
|
56
|
-
// fetch project from your DB
|
|
57
|
-
return {
|
|
58
|
-
id: projectId,
|
|
59
|
-
name: 'Demo Project',
|
|
60
|
-
description: 'Demo for StreamBy integration',
|
|
61
|
-
rootFolders: [],
|
|
62
|
-
settings: { allowUpload: true }
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
}));
|
|
66
|
-
|
|
67
|
-
app.listen(3000);
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
---
|
|
71
|
-
|
|
72
|
-
## ๐งช Testing
|
|
73
|
-
|
|
74
|
-
```bash
|
|
75
|
-
npm run test
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
Unit tests use [Vitest](https://vitest.dev) and [Supertest](https://www.npmjs.com/package/supertest).
|
|
79
|
-
|
|
80
|
-
---
|
|
81
|
-
|
|
82
|
-
## ๐ Features
|
|
83
|
-
|
|
84
|
-
- ๐ Multi-project access control
|
|
85
|
-
- ๐ Project-aware file uploads & listings
|
|
86
|
-
- ๐งน Modular adapters per storage provider
|
|
87
|
-
- ๐งฐ Built-in testability with mock auth & storage
|
|
88
|
-
- โจ Simple to extend for custom business logic
|
|
89
|
-
|
|
90
|
-
---
|
|
91
|
-
|
|
92
|
-
## ๐ฃ Roadmap
|
|
93
|
-
|
|
94
|
-
- [ ] Support for Google Cloud Storage
|
|
95
|
-
- [ ] CLI tool for uploading files
|
|
96
|
-
- [ ] Role-based access control middleware
|
|
97
|
-
- [ ] Plugin system for extended routes
|
|
98
|
-
- [ ] Streaming support (HLS, audio, etc.)
|
|
99
|
-
|
|
100
|
-
---
|
|
101
|
-
|
|
102
|
-
## ๐งโ๐ป Maintained by
|
|
103
|
-
|
|
104
|
-
**TerminalCore Labs** โ part of [Nhexa Entertainment](https://nhexa.cl)
|
|
105
|
-
Developed as open-source infrastructure for creative and media-oriented apps.
|
|
106
|
-
|
|
107
|
-
Visit us [here](https://terminalcore.cl)
|
|
108
|
-
|
|
109
|
-
---
|
|
110
|
-
|
|
111
|
-
## ๐ License
|
|
112
|
-
|
|
113
|
-
[MIT](./LICENSE)
|
|
114
|
-
|
|
1
|
+
# @streamby/core
|
|
2
|
+
|
|
3
|
+
Middleware framework for building storage-agnostic media APIs.
|
|
4
|
+
Part of the [StreamBy](https://streamby.nhexa.cl) ecosystem by TerminalCore Labs.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## ๐ What is it?
|
|
9
|
+
|
|
10
|
+
`@streamby/core` is a plug-and-play middleware for Express (or compatible frameworks) that enables file uploads, listings and **multi-project access** over services like:
|
|
11
|
+
|
|
12
|
+
- โ
AWS S3
|
|
13
|
+
- โ
Google Cloud Storage (soon)
|
|
14
|
+
- โ
Cloudflare R2 (soon)
|
|
15
|
+
- โ
Local/Personal servers (soon)
|
|
16
|
+
|
|
17
|
+
It's designed to be installed inside your existing API as a library โ **no need to run a separate backend**.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## ๐ฆ Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install @streamby/core
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## ๐งฑ Basic usage
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import express from 'express';
|
|
33
|
+
import { createStreamByRouter } from '@streamby/core';
|
|
34
|
+
|
|
35
|
+
const app = express();
|
|
36
|
+
|
|
37
|
+
app.use('/streamby', createStreamByRouter({
|
|
38
|
+
storageProvider: {
|
|
39
|
+
type: 's3',
|
|
40
|
+
config: {
|
|
41
|
+
bucket: 'your-bucket-name',
|
|
42
|
+
region: 'your-region',
|
|
43
|
+
accessKeyId: 'YOUR_AWS_KEY',
|
|
44
|
+
secretAccessKey: 'YOUR_AWS_SECRET'
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
authProvider: async (req) => {
|
|
48
|
+
// extract token/cookie and validate
|
|
49
|
+
return {
|
|
50
|
+
userId: 'demo',
|
|
51
|
+
projects: ['demo-project'],
|
|
52
|
+
role: 'admin',
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
projectProvider: async (projectId) => {
|
|
56
|
+
// fetch project from your DB
|
|
57
|
+
return {
|
|
58
|
+
id: projectId,
|
|
59
|
+
name: 'Demo Project',
|
|
60
|
+
description: 'Demo for StreamBy integration',
|
|
61
|
+
rootFolders: [],
|
|
62
|
+
settings: { allowUpload: true }
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}));
|
|
66
|
+
|
|
67
|
+
app.listen(3000);
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## ๐งช Testing
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
npm run test
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Unit tests use [Vitest](https://vitest.dev) and [Supertest](https://www.npmjs.com/package/supertest).
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## ๐ Features
|
|
83
|
+
|
|
84
|
+
- ๐ Multi-project access control
|
|
85
|
+
- ๐ Project-aware file uploads & listings
|
|
86
|
+
- ๐งน Modular adapters per storage provider
|
|
87
|
+
- ๐งฐ Built-in testability with mock auth & storage
|
|
88
|
+
- โจ Simple to extend for custom business logic
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## ๐ฃ Roadmap
|
|
93
|
+
|
|
94
|
+
- [ ] Support for Google Cloud Storage
|
|
95
|
+
- [ ] CLI tool for uploading files
|
|
96
|
+
- [ ] Role-based access control middleware
|
|
97
|
+
- [ ] Plugin system for extended routes
|
|
98
|
+
- [ ] Streaming support (HLS, audio, etc.)
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## ๐งโ๐ป Maintained by
|
|
103
|
+
|
|
104
|
+
**TerminalCore Labs** โ part of [Nhexa Entertainment](https://nhexa.cl)
|
|
105
|
+
Developed as open-source infrastructure for creative and media-oriented apps.
|
|
106
|
+
|
|
107
|
+
Visit us [here](https://terminalcore.cl)
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## ๐ License
|
|
112
|
+
|
|
113
|
+
[MIT](./LICENSE)
|
|
114
|
+
|
package/dist/adapters/s3.js
CHANGED
|
@@ -12,27 +12,15 @@ function createS3Adapter(config) {
|
|
|
12
12
|
},
|
|
13
13
|
});
|
|
14
14
|
return {
|
|
15
|
-
async getPresignedUrl(filename, contentType) {
|
|
16
|
-
const
|
|
17
|
-
Bucket: config.bucket,
|
|
18
|
-
Key: `uploads/${filename}`,
|
|
19
|
-
ContentType: contentType,
|
|
20
|
-
});
|
|
21
|
-
return (0, s3_request_presigner_1.getSignedUrl)(s3, command, { expiresIn: 3600 });
|
|
22
|
-
},
|
|
23
|
-
async uploadFile(req, projectId) {
|
|
24
|
-
const file = req.body?.file;
|
|
25
|
-
if (!file || !file.name || !file.buffer) {
|
|
26
|
-
throw new Error('Invalid file upload: missing name or buffer');
|
|
27
|
-
}
|
|
28
|
-
const key = `${projectId}/${file.name}`;
|
|
15
|
+
async getPresignedUrl(filename, contentType, projectId) {
|
|
16
|
+
const key = `${projectId}/file-${Date.now()}-${filename}`;
|
|
29
17
|
const command = new client_s3_1.PutObjectCommand({
|
|
30
18
|
Bucket: config.bucket,
|
|
31
19
|
Key: key,
|
|
32
|
-
|
|
20
|
+
ContentType: contentType,
|
|
33
21
|
});
|
|
34
|
-
await
|
|
35
|
-
return {
|
|
22
|
+
const url = await (0, s3_request_presigner_1.getSignedUrl)(s3, command, { expiresIn: 60 });
|
|
23
|
+
return { url, key };
|
|
36
24
|
},
|
|
37
25
|
async listFiles(projectId) {
|
|
38
26
|
const command = new client_s3_1.ListObjectsV2Command({
|
|
@@ -34,12 +34,12 @@ function createStreamByRouter(config) {
|
|
|
34
34
|
if (auth.role !== 'admin' && auth.role !== 'editor') {
|
|
35
35
|
return res.status(403).json({ error: 'Permission denied' });
|
|
36
36
|
}
|
|
37
|
-
const { filename, contentType } = req.body;
|
|
38
|
-
if (!filename || !contentType) {
|
|
39
|
-
return res.status(400).json({ error: 'Missing filename or
|
|
37
|
+
const { filename, contentType, projectId } = req.body;
|
|
38
|
+
if (!filename || !contentType || !projectId) {
|
|
39
|
+
return res.status(400).json({ error: 'Missing filename, contentType, or projectId' });
|
|
40
40
|
}
|
|
41
|
-
const url = await (0, presign_1.getPresignedUrl)(adapter, filename, contentType);
|
|
42
|
-
res.json(
|
|
41
|
+
const url = await (0, presign_1.getPresignedUrl)(adapter, filename, contentType, projectId);
|
|
42
|
+
res.json(url);
|
|
43
43
|
}
|
|
44
44
|
catch (err) {
|
|
45
45
|
res.status(500).json({ error: 'Failed to generate presigned URL', details: err.message });
|
|
@@ -59,36 +59,22 @@ function createStreamByRouter(config) {
|
|
|
59
59
|
res.status(500).json({ error: 'Failed to list files', details: err });
|
|
60
60
|
}
|
|
61
61
|
});
|
|
62
|
-
router.patch('/projects/:id
|
|
62
|
+
router.patch('/projects/:id', async (req, res) => {
|
|
63
63
|
try {
|
|
64
64
|
const auth = await config.authProvider(req);
|
|
65
65
|
if (auth.role !== 'admin' && auth.role !== 'editor') {
|
|
66
66
|
return res.status(403).json({ error: 'Permission denied' });
|
|
67
67
|
}
|
|
68
68
|
const projectId = req.params.id;
|
|
69
|
-
const
|
|
70
|
-
if (!
|
|
71
|
-
return res.status(400).json({ error: 'Missing
|
|
69
|
+
const updates = req.body;
|
|
70
|
+
if (!updates || typeof updates !== 'object') {
|
|
71
|
+
return res.status(400).json({ error: 'Missing updates payload' });
|
|
72
72
|
}
|
|
73
|
-
const updated = await config.projectProvider.
|
|
74
|
-
res.status(200).json(updated);
|
|
73
|
+
const updated = await config.projectProvider.update(projectId, updates);
|
|
74
|
+
res.status(200).json({ success: true, project: updated });
|
|
75
75
|
}
|
|
76
76
|
catch (err) {
|
|
77
|
-
res.status(500).json({ error: 'Failed to update project
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
router.post('/upload', async (req, res) => {
|
|
81
|
-
try {
|
|
82
|
-
const auth = await config.authProvider(req);
|
|
83
|
-
const projectId = (req.query.projectId || req.headers['x-project-id']);
|
|
84
|
-
if (!projectId || !auth.projects.includes(projectId)) {
|
|
85
|
-
return res.status(403).json({ error: 'Unauthorized or missing projectId' });
|
|
86
|
-
}
|
|
87
|
-
const result = await (0, file_1.uploadFileService)(adapter, req, projectId);
|
|
88
|
-
res.json(result);
|
|
89
|
-
}
|
|
90
|
-
catch (err) {
|
|
91
|
-
res.status(500).json({ error: 'Failed to upload file', details: err });
|
|
77
|
+
res.status(500).json({ error: 'Failed to update project', details: err.message });
|
|
92
78
|
}
|
|
93
79
|
});
|
|
94
80
|
router.get('/projects/:id', async (req, res) => {
|
package/dist/services/file.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
import { StorageAdapter } from '../types';
|
|
2
2
|
import { Request } from 'express';
|
|
3
3
|
export declare function listFilesService(adapter: StorageAdapter, req: Request, projectId: string): Promise<any[]>;
|
|
4
|
-
export declare function uploadFileService(adapter: StorageAdapter, req: Request, projectId: string): Promise<any>;
|
package/dist/services/file.js
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.listFilesService = listFilesService;
|
|
4
|
-
exports.uploadFileService = uploadFileService;
|
|
5
4
|
async function listFilesService(adapter, req, projectId) {
|
|
6
5
|
return adapter.listFiles(projectId);
|
|
7
6
|
}
|
|
8
|
-
async function uploadFileService(adapter, req, projectId) {
|
|
9
|
-
return adapter.uploadFile(req, projectId);
|
|
10
|
-
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { StorageAdapter } from '../types';
|
|
2
|
-
export declare function getPresignedUrl(adapter: StorageAdapter, filename: string, contentType: string): Promise<
|
|
2
|
+
export declare function getPresignedUrl(adapter: StorageAdapter, filename: string, contentType: string, projectId: string): Promise<any>;
|
package/dist/services/presign.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getPresignedUrl = getPresignedUrl;
|
|
4
|
-
async function getPresignedUrl(adapter, filename, contentType) {
|
|
4
|
+
async function getPresignedUrl(adapter, filename, contentType, projectId) {
|
|
5
5
|
if (!('getPresignedUrl' in adapter)) {
|
|
6
6
|
throw new Error('StorageAdapter does not support presigned URLs');
|
|
7
7
|
}
|
|
8
|
-
return adapter.getPresignedUrl(filename, contentType);
|
|
8
|
+
return adapter.getPresignedUrl(filename, contentType, projectId);
|
|
9
9
|
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -7,9 +7,8 @@ export interface S3Config {
|
|
|
7
7
|
}
|
|
8
8
|
export type StorageProviderType = 's3';
|
|
9
9
|
export interface StorageAdapter {
|
|
10
|
-
uploadFile(req: Request, projectId: string): Promise<any>;
|
|
11
10
|
listFiles(projectId: string): Promise<any[]>;
|
|
12
|
-
getPresignedUrl?: (filename: string, contentType: string) => Promise<
|
|
11
|
+
getPresignedUrl?: (filename: string, contentType: string, projectId: string) => Promise<any>;
|
|
13
12
|
}
|
|
14
13
|
export interface ProjectInfo {
|
|
15
14
|
id: string;
|
|
@@ -44,7 +43,7 @@ export interface AuthContext {
|
|
|
44
43
|
export type AuthProvider = (req: Request) => Promise<AuthContext>;
|
|
45
44
|
export interface ProjectProvider {
|
|
46
45
|
getById(projectId: string): Promise<ProjectInfo>;
|
|
47
|
-
|
|
46
|
+
update(projectId: string, updates: Partial<Omit<ProjectInfo, 'id' | 'rootFolders'>>): Promise<ProjectInfo>;
|
|
48
47
|
create(data: {
|
|
49
48
|
name: string;
|
|
50
49
|
image?: string;
|
package/package.json
CHANGED
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "streamby-core",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "StreamBy middleware framework for media storage management",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"types": "dist/index.d.ts",
|
|
7
|
-
"files": [
|
|
8
|
-
"dist"
|
|
9
|
-
],
|
|
10
|
-
"scripts": {
|
|
11
|
-
"build": "tsc",
|
|
12
|
-
"test": "vitest",
|
|
13
|
-
"dev": "tsc --watch",
|
|
14
|
-
"prepublishOnly": "npm run build"
|
|
15
|
-
},
|
|
16
|
-
"repository": {
|
|
17
|
-
"type": "git",
|
|
18
|
-
"url": "https://github.com/GwerhDev/StreamBy-Package.git"
|
|
19
|
-
},
|
|
20
|
-
"keywords": [
|
|
21
|
-
"streamby",
|
|
22
|
-
"middleware",
|
|
23
|
-
"upload",
|
|
24
|
-
"storage",
|
|
25
|
-
"s3",
|
|
26
|
-
"express",
|
|
27
|
-
"typescript"
|
|
28
|
-
],
|
|
29
|
-
"author": "TerminalCore Labs",
|
|
30
|
-
"license": "MIT",
|
|
31
|
-
"dependencies": {
|
|
32
|
-
"@aws-sdk/client-s3": "^3.528.0",
|
|
33
|
-
"@aws-sdk/s3-request-presigner": "^3.787.0",
|
|
34
|
-
"express": "^4.0.0"
|
|
35
|
-
},
|
|
36
|
-
"devDependencies": {
|
|
37
|
-
"@types/express": "^4.17.17",
|
|
38
|
-
"@types/supertest": "^6.0.3",
|
|
39
|
-
"supertest": "^7.1.0",
|
|
40
|
-
"typescript": "^5.8.3",
|
|
41
|
-
"vitest": "^3.1.1"
|
|
42
|
-
},
|
|
43
|
-
"peerDependencies": {
|
|
44
|
-
"express": "^4.0.0"
|
|
45
|
-
}
|
|
46
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "streamby-core",
|
|
3
|
+
"version": "0.8.1",
|
|
4
|
+
"description": "StreamBy middleware framework for media storage management",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"test": "vitest",
|
|
13
|
+
"dev": "tsc --watch",
|
|
14
|
+
"prepublishOnly": "npm run build"
|
|
15
|
+
},
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/GwerhDev/StreamBy-Package.git"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"streamby",
|
|
22
|
+
"middleware",
|
|
23
|
+
"upload",
|
|
24
|
+
"storage",
|
|
25
|
+
"s3",
|
|
26
|
+
"express",
|
|
27
|
+
"typescript"
|
|
28
|
+
],
|
|
29
|
+
"author": "TerminalCore Labs",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@aws-sdk/client-s3": "^3.528.0",
|
|
33
|
+
"@aws-sdk/s3-request-presigner": "^3.787.0",
|
|
34
|
+
"express": "^4.0.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/express": "^4.17.17",
|
|
38
|
+
"@types/supertest": "^6.0.3",
|
|
39
|
+
"supertest": "^7.1.0",
|
|
40
|
+
"typescript": "^5.8.3",
|
|
41
|
+
"vitest": "^3.1.1"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"express": "^4.0.0"
|
|
45
|
+
}
|
|
46
|
+
}
|