@araminix/platform 0.0.0-stage โ 1.7.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/LICENSE +21 -0
- package/README.md +282 -2
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/src/Platform.d.ts +59 -0
- package/dist/src/Platform.d.ts.map +1 -0
- package/dist/src/Platform.js +415 -0
- package/dist/src/Platform.js.map +1 -0
- package/dist/src/agent/AgentController.d.ts +41 -0
- package/dist/src/agent/AgentController.d.ts.map +1 -0
- package/dist/src/agent/AgentController.js +332 -0
- package/dist/src/agent/AgentController.js.map +1 -0
- package/dist/src/agent/agentWorkerDriver.d.ts +11 -0
- package/dist/src/agent/agentWorkerDriver.d.ts.map +1 -0
- package/dist/src/agent/agentWorkerDriver.js +20 -0
- package/dist/src/agent/agentWorkerDriver.js.map +1 -0
- package/dist/src/agent/d.d.ts +39 -0
- package/dist/src/agent/d.d.ts.map +1 -0
- package/dist/src/agent/d.js +91 -0
- package/dist/src/agent/d.js.map +1 -0
- package/dist/src/agent/worker.d.ts +2 -0
- package/dist/src/agent/worker.d.ts.map +1 -0
- package/dist/src/agent/worker.js +72 -0
- package/dist/src/agent/worker.js.map +1 -0
- package/dist/src/builder/Fragment.d.ts +40 -0
- package/dist/src/builder/Fragment.d.ts.map +1 -0
- package/dist/src/builder/Fragment.js +87 -0
- package/dist/src/builder/Fragment.js.map +1 -0
- package/dist/src/builder/Panel.d.ts +30 -0
- package/dist/src/builder/Panel.d.ts.map +1 -0
- package/dist/src/builder/Panel.js +45 -0
- package/dist/src/builder/Panel.js.map +1 -0
- package/dist/src/builder/builder.d.ts +31 -0
- package/dist/src/builder/builder.d.ts.map +1 -0
- package/dist/src/builder/builder.js +43 -0
- package/dist/src/builder/builder.js.map +1 -0
- package/dist/src/executor/ActivityInstance.d.ts +98 -0
- package/dist/src/executor/ActivityInstance.d.ts.map +1 -0
- package/dist/src/executor/ActivityInstance.js +389 -0
- package/dist/src/executor/ActivityInstance.js.map +1 -0
- package/dist/src/executor/AppInstance.d.ts +73 -0
- package/dist/src/executor/AppInstance.d.ts.map +1 -0
- package/dist/src/executor/AppInstance.js +399 -0
- package/dist/src/executor/AppInstance.js.map +1 -0
- package/dist/src/executor/Instance.d.ts +43 -0
- package/dist/src/executor/Instance.d.ts.map +1 -0
- package/dist/src/executor/Instance.js +415 -0
- package/dist/src/executor/Instance.js.map +1 -0
- package/dist/src/executor/index.d.ts +4 -0
- package/dist/src/executor/index.d.ts.map +1 -0
- package/dist/src/executor/index.js +3 -0
- package/dist/src/executor/index.js.map +1 -0
- package/dist/src/executor/proto.d.ts +120 -0
- package/dist/src/executor/proto.d.ts.map +1 -0
- package/dist/src/executor/proto.js +207 -0
- package/dist/src/executor/proto.js.map +1 -0
- package/dist/src/executor/worker.d.ts +2 -0
- package/dist/src/executor/worker.d.ts.map +1 -0
- package/dist/src/executor/worker.js +154 -0
- package/dist/src/executor/worker.js.map +1 -0
- package/dist/src/executor/workerDriver.d.ts +14 -0
- package/dist/src/executor/workerDriver.d.ts.map +1 -0
- package/dist/src/executor/workerDriver.js +26 -0
- package/dist/src/executor/workerDriver.js.map +1 -0
- package/dist/src/lib/actors.d.ts +94 -0
- package/dist/src/lib/actors.d.ts.map +1 -0
- package/dist/src/lib/actors.js +139 -0
- package/dist/src/lib/actors.js.map +1 -0
- package/dist/src/lib/d.d.ts +145 -0
- package/dist/src/lib/d.d.ts.map +1 -0
- package/dist/src/lib/d.js +296 -0
- package/dist/src/lib/d.js.map +1 -0
- package/dist/src/lib/worker_socket.d.ts +56 -0
- package/dist/src/lib/worker_socket.d.ts.map +1 -0
- package/dist/src/lib/worker_socket.js +161 -0
- package/dist/src/lib/worker_socket.js.map +1 -0
- package/dist/src/server/AuthProvider.d.ts +199 -0
- package/dist/src/server/AuthProvider.d.ts.map +1 -0
- package/dist/src/server/AuthProvider.js +69 -0
- package/dist/src/server/AuthProvider.js.map +1 -0
- package/dist/src/server/ConnectRequest.d.ts +15 -0
- package/dist/src/server/ConnectRequest.d.ts.map +1 -0
- package/dist/src/server/ConnectRequest.js +36 -0
- package/dist/src/server/ConnectRequest.js.map +1 -0
- package/dist/src/server/Endpoint.d.ts +78 -0
- package/dist/src/server/Endpoint.d.ts.map +1 -0
- package/dist/src/server/Endpoint.js +809 -0
- package/dist/src/server/Endpoint.js.map +1 -0
- package/dist/src/server/EndpointController.d.ts +15 -0
- package/dist/src/server/EndpointController.d.ts.map +1 -0
- package/dist/src/server/EndpointController.js +92 -0
- package/dist/src/server/EndpointController.js.map +1 -0
- package/dist/src/server/index.d.ts +8 -0
- package/dist/src/server/index.d.ts.map +1 -0
- package/dist/src/server/index.js +8 -0
- package/dist/src/server/index.js.map +1 -0
- package/dist/src/utils/i18n.d.ts +20 -0
- package/dist/src/utils/i18n.d.ts.map +1 -0
- package/dist/src/utils/i18n.js +41 -0
- package/dist/src/utils/i18n.js.map +1 -0
- package/dist/src/utils/index.d.ts +4 -0
- package/dist/src/utils/index.d.ts.map +1 -0
- package/dist/src/utils/index.js +4 -0
- package/dist/src/utils/index.js.map +1 -0
- package/dist/src/utils/log_middleware.d.ts +3 -0
- package/dist/src/utils/log_middleware.d.ts.map +1 -0
- package/dist/src/utils/log_middleware.js +38 -0
- package/dist/src/utils/log_middleware.js.map +1 -0
- package/dist/src/utils/minioService.d.ts +54 -0
- package/dist/src/utils/minioService.d.ts.map +1 -0
- package/dist/src/utils/minioService.js +166 -0
- package/dist/src/utils/minioService.js.map +1 -0
- package/dist/tests/actors.test.d.ts +2 -0
- package/dist/tests/actors.test.d.ts.map +1 -0
- package/dist/tests/actors.test.js +45 -0
- package/dist/tests/actors.test.js.map +1 -0
- package/dist/tests/agentWorker.test.d.ts +2 -0
- package/dist/tests/agentWorker.test.d.ts.map +1 -0
- package/dist/tests/agentWorker.test.js +225 -0
- package/dist/tests/agentWorker.test.js.map +1 -0
- package/dist/tests/authProvider.test.d.ts +2 -0
- package/dist/tests/authProvider.test.d.ts.map +1 -0
- package/dist/tests/authProvider.test.js +39 -0
- package/dist/tests/authProvider.test.js.map +1 -0
- package/dist/tests/builder.test.d.ts +2 -0
- package/dist/tests/builder.test.d.ts.map +1 -0
- package/dist/tests/builder.test.js +37 -0
- package/dist/tests/builder.test.js.map +1 -0
- package/dist/tests/connectRequest.test.d.ts +2 -0
- package/dist/tests/connectRequest.test.d.ts.map +1 -0
- package/dist/tests/connectRequest.test.js +55 -0
- package/dist/tests/connectRequest.test.js.map +1 -0
- package/dist/tests/endpointController.test.d.ts +2 -0
- package/dist/tests/endpointController.test.d.ts.map +1 -0
- package/dist/tests/endpointController.test.js +28 -0
- package/dist/tests/endpointController.test.js.map +1 -0
- package/dist/tests/endpointSecurity.test.d.ts +2 -0
- package/dist/tests/endpointSecurity.test.d.ts.map +1 -0
- package/dist/tests/endpointSecurity.test.js +1007 -0
- package/dist/tests/endpointSecurity.test.js.map +1 -0
- package/dist/tests/i18n.test.d.ts +2 -0
- package/dist/tests/i18n.test.d.ts.map +1 -0
- package/dist/tests/i18n.test.js +25 -0
- package/dist/tests/i18n.test.js.map +1 -0
- package/dist/tests/logMiddleware.test.d.ts +2 -0
- package/dist/tests/logMiddleware.test.d.ts.map +1 -0
- package/dist/tests/logMiddleware.test.js +60 -0
- package/dist/tests/logMiddleware.test.js.map +1 -0
- package/dist/tests/minioService.test.d.ts +2 -0
- package/dist/tests/minioService.test.d.ts.map +1 -0
- package/dist/tests/minioService.test.js +206 -0
- package/dist/tests/minioService.test.js.map +1 -0
- package/dist/tests/platform.test.d.ts +2 -0
- package/dist/tests/platform.test.d.ts.map +1 -0
- package/dist/tests/platform.test.js +288 -0
- package/dist/tests/platform.test.js.map +1 -0
- package/dist/tests/proto.test.d.ts +2 -0
- package/dist/tests/proto.test.d.ts.map +1 -0
- package/dist/tests/proto.test.js +37 -0
- package/dist/tests/proto.test.js.map +1 -0
- package/dist/tests/unhandledRejections.test.d.ts +2 -0
- package/dist/tests/unhandledRejections.test.d.ts.map +1 -0
- package/dist/tests/unhandledRejections.test.js +204 -0
- package/dist/tests/unhandledRejections.test.js.map +1 -0
- package/dist/tests/uploadSecurity.test.d.ts +2 -0
- package/dist/tests/uploadSecurity.test.d.ts.map +1 -0
- package/dist/tests/uploadSecurity.test.js +219 -0
- package/dist/tests/uploadSecurity.test.js.map +1 -0
- package/dist/tests/workerSocket.test.d.ts +2 -0
- package/dist/tests/workerSocket.test.d.ts.map +1 -0
- package/dist/tests/workerSocket.test.js +53 -0
- package/dist/tests/workerSocket.test.js.map +1 -0
- package/package.json +70 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Amin Abbasi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,283 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @araminix/platform
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> **Enterprise-grade actor runtime, WebSocket endpoint platform, and multi-threaded agent execution engine.**
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@araminix/platform)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://www.typescriptlang.org/)
|
|
8
|
+
[](https://nodejs.org/)
|
|
9
|
+
|
|
10
|
+
**Araminix Platform** (`@araminix/platform`) is a high-performance backend orchestration engine designed for complex real-time applications. Built on top of [`@araminix/lib`](../araminix-lib), it integrates an enterprise WebSocket & HTTP server, worker-thread agent execution, dynamic component/UI assembly, authentication (with 2FA and Google OAuth), and S3/MinIO cloud storage.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## ๐ Key Features
|
|
15
|
+
|
|
16
|
+
- โก **Unified WebSocket & HTTP Endpoint**: Built on Express & `express-ws`, providing automatic WebSocket route dispatching, session cookies, Google OAuth, and two-factor authentication (2FA).
|
|
17
|
+
- ๐งต **Multi-Threaded Agent Runtime**: Spawns isolated worker processes (`worker_threads`) with type-safe `MessageChannel` IPC, protecting the main thread from CPU-heavy tasks and crashes.
|
|
18
|
+
- ๐งฉ **Dynamic UI Builder & Actor Engine**: Assemble complex interactive interfaces on the fly using `Panel`, `Fragment`, and `Actor` lifecycles.
|
|
19
|
+
- ๐๏ธ **Integrated MinIO / S3 Storage**: Built-in presigned URL generation, file uploads (`multer`), MIME type mapping, and bucket management.
|
|
20
|
+
- ๐ **First-Class Internationalization**: Integrated `I18nService` with type-safe generic dictionary translations and automatic language fallbacks.
|
|
21
|
+
- ๐ก๏ธ **Zero-Crash Functional Core**: Powered by `@araminix/lib`'s `Result<T, E>` monads and multiplexed streaming channels.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## ๐ Architecture
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
+------------------------------------+
|
|
29
|
+
| Platform |
|
|
30
|
+
+-----------------+------------------+
|
|
31
|
+
|
|
|
32
|
+
+-----------------------------+-----------------------------+
|
|
33
|
+
| |
|
|
34
|
+
v v
|
|
35
|
+
+----------------------------+ +----------------------------+
|
|
36
|
+
| Endpoint | | AgentController |
|
|
37
|
+
| (Express WS + HTTP + 2FA) | | (worker_threads) |
|
|
38
|
+
+--------------+-------------+ +--------------+-------------+
|
|
39
|
+
| |
|
|
40
|
+
+--------------+-------------+ +--------------+-------------+
|
|
41
|
+
| MinIO S3 / Storage | | WorkerSocket / IPC Port |
|
|
42
|
+
+----------------------------+ +----------------------------+
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## ๐ฆ Installation
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# npm
|
|
51
|
+
npm install @araminix/platform @araminix/lib
|
|
52
|
+
|
|
53
|
+
# pnpm
|
|
54
|
+
pnpm add @araminix/platform @araminix/lib
|
|
55
|
+
|
|
56
|
+
# yarn
|
|
57
|
+
yarn add @araminix/platform @araminix/lib
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## ๐ Quick Start
|
|
63
|
+
|
|
64
|
+
### 1. Initializing the Platform and Endpoint
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { AuthProvider, ClientInfo, Ok, Platform, Result } from '@araminix/platform';
|
|
68
|
+
|
|
69
|
+
// 1. Define custom authentication logic
|
|
70
|
+
class CustomAuthProvider extends AuthProvider {
|
|
71
|
+
async getInfo(token: string): Promise<Result<ClientInfo, unknown>> {
|
|
72
|
+
// Retrieve and return client information
|
|
73
|
+
return new Ok({
|
|
74
|
+
id: 'user-100',
|
|
75
|
+
clientType: 'User',
|
|
76
|
+
runtimeId: 'rt-100',
|
|
77
|
+
} as ClientInfo);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async auth(data: any) {
|
|
81
|
+
/* verify credentials */ return new Ok('token-xyz');
|
|
82
|
+
}
|
|
83
|
+
async googleAuth(data: any) {
|
|
84
|
+
/* Google OAuth */ return new Ok('token-xyz');
|
|
85
|
+
}
|
|
86
|
+
async destroy(token: string) {
|
|
87
|
+
/* session cleanup */
|
|
88
|
+
}
|
|
89
|
+
async refreshToken(token: string) {
|
|
90
|
+
return new Ok('new-token');
|
|
91
|
+
}
|
|
92
|
+
async request2FA(userId: string) {
|
|
93
|
+
return new Ok('otpauth://...');
|
|
94
|
+
}
|
|
95
|
+
async enable2FA(userId: string, secret: string, code: string) {
|
|
96
|
+
return new Ok(true);
|
|
97
|
+
}
|
|
98
|
+
async verify2FA(account: string, code: string, uuid: string) {
|
|
99
|
+
return new Ok(true);
|
|
100
|
+
}
|
|
101
|
+
async disable2FA(userId: string) {
|
|
102
|
+
return new Ok(true);
|
|
103
|
+
}
|
|
104
|
+
async requestUploadUrl(id: string, name: string, mime: string) {
|
|
105
|
+
return new Ok('https://...');
|
|
106
|
+
}
|
|
107
|
+
async requestDownloadUrl(id: string, name: string) {
|
|
108
|
+
return new Ok('https://...');
|
|
109
|
+
}
|
|
110
|
+
async mobileRequests(data: any) {
|
|
111
|
+
return { status: 200, result: 'OK' };
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// 2. Configure and launch the Platform
|
|
116
|
+
const platform = new Platform({
|
|
117
|
+
appIndexPath: new URL('file:///path/to/apps/index.js'),
|
|
118
|
+
agentIndexPath: new URL('file:///path/to/agents/index.js'),
|
|
119
|
+
authProvider: new CustomAuthProvider(),
|
|
120
|
+
instanceUserLimit: 10,
|
|
121
|
+
port: 3000,
|
|
122
|
+
mount: '/api',
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Start listening for HTTP & WebSocket connections
|
|
126
|
+
await platform.start();
|
|
127
|
+
console.log('Araminix Platform running on http://localhost:3000/api');
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
### 2. Spawning Multi-Threaded Agents
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
import { AgentController } from '@araminix/platform';
|
|
136
|
+
|
|
137
|
+
const controller = new AgentController(new URL('file:///path/to/agentWorker.js'));
|
|
138
|
+
|
|
139
|
+
// Acquire or send tasks to background worker threads
|
|
140
|
+
const taskResult = await controller.task('worker-1', {
|
|
141
|
+
action: 'computeAnalytics',
|
|
142
|
+
payload: { range: '30d' },
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
if (taskResult.isOk()) {
|
|
146
|
+
console.log('Agent Response:', taskResult.unwrap());
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
### 3. Dynamic UI Building with Fragments & Panels
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
import { Fragment, panel } from '@araminix/platform';
|
|
156
|
+
|
|
157
|
+
class UserProfileFragment extends Fragment {
|
|
158
|
+
build() {
|
|
159
|
+
return {
|
|
160
|
+
type: 'card',
|
|
161
|
+
props: { title: 'User Information' },
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Assemble nested reactive panels
|
|
167
|
+
const dashboard = panel({ header: 'System Overview' })
|
|
168
|
+
.panel(panel({ header: 'Metrics' }))
|
|
169
|
+
.fragment(new UserProfileFragment())
|
|
170
|
+
.build();
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
### 4. Session Security & Cookie Configuration
|
|
176
|
+
|
|
177
|
+
`Endpoint` issues signed, hardened session cookies by default:
|
|
178
|
+
|
|
179
|
+
- Default Flags: `HttpOnly: true`, `Secure: true`, `SameSite: 'lax'`, `Path: '/'`, and TTL-based `Max-Age`.
|
|
180
|
+
- Customizable via optional `cookieOptions` in `EndpointOptions`:
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
const endpoint = new Endpoint({
|
|
184
|
+
authProvider: new CustomAuthProvider(),
|
|
185
|
+
cookieOptions: {
|
|
186
|
+
secure: process.env.NODE_ENV === 'production',
|
|
187
|
+
sameSite: 'lax',
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
#### WebSocket Authentication Routes
|
|
193
|
+
|
|
194
|
+
- **`/ws/:endpoint` (Recommended):**
|
|
195
|
+
- **Browsers:** Cookie-authenticated via `httpOnly` session cookie automatically attached on WebSocket upgrade.
|
|
196
|
+
- **Node Clients / Agents:** Header-authenticated by passing `x-token: <token>` in the HTTP upgrade request headers.
|
|
197
|
+
- **`/ws-token/:token/:endpoint` (`@deprecated`):**
|
|
198
|
+
- Maintained for backward compatibility with legacy clients. Tokens in URL paths are automatically redacted in server access logs.
|
|
199
|
+
|
|
200
|
+
#### Google OAuth Hardening (`/gauth`)
|
|
201
|
+
|
|
202
|
+
`Endpoint` verifies Google access tokens against Google's `tokeninfo` endpoint prior to retrieving user profile data:
|
|
203
|
+
|
|
204
|
+
- **Client ID Verification:** `EndpointOptions.googleClientIds` defines allowed OAuth client IDs. Replayed tokens issued to other Google OAuth applications are rejected with HTTP 401 (`Unauthorized`).
|
|
205
|
+
- **Verified Email Enforcement:** Rejects tokens unless Google confirms `email_verified === 'true'`.
|
|
206
|
+
- **Header-Only Authorization:** Access tokens are passed to `userinfo` strictly via the HTTP `Authorization: Bearer <token>` header rather than query strings.
|
|
207
|
+
- **Fail-Closed Protection:** If `googleClientIds` is not configured, `/gauth` requests are refused with HTTP 503 (`Service Unavailable`).
|
|
208
|
+
- **HTTP Timeouts:** All external Google API calls enforce an explicit 10-second timeout.
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
const endpoint = new Endpoint({
|
|
212
|
+
authProvider: new CustomAuthProvider(),
|
|
213
|
+
googleClientIds: [
|
|
214
|
+
'1234567890-example.apps.googleusercontent.com',
|
|
215
|
+
],
|
|
216
|
+
});
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
### 5. File Upload Security & Stored XSS Mitigation
|
|
222
|
+
|
|
223
|
+
`Endpoint` and `Platform` provide hardened file upload and static download controls:
|
|
224
|
+
|
|
225
|
+
- **Upload Size Limits:** Configured via `maxUploadBytes` (default: 20 MB). Oversized files are rejected with HTTP 413 (`Payload Too Large`). Only single-file uploads (`files: 1`) are permitted per request.
|
|
226
|
+
- **Allowlist Filtering:** Optional `uploadAllowlist` restricts uploads to specific extensions and/or MIME types. Unauthorized uploads are rejected with HTTP 415 (`Unsupported Media Type`):
|
|
227
|
+
```typescript
|
|
228
|
+
const platform = new Platform({
|
|
229
|
+
uploadDir: '/var/data/uploads',
|
|
230
|
+
maxUploadBytes: 10 * 1024 * 1024, // 10 MB
|
|
231
|
+
uploadAllowlist: {
|
|
232
|
+
extensions: ['png', 'jpg', 'pdf'],
|
|
233
|
+
mimetypes: ['image/png', 'image/jpeg', 'application/pdf'],
|
|
234
|
+
},
|
|
235
|
+
// ...
|
|
236
|
+
});
|
|
237
|
+
```
|
|
238
|
+
- **Filename Sanitization:** Uploaded filenames are stripped of path traversal sequences (`..`, `/`, `\`), null bytes, and non-printable control characters, with length capped at 255 characters.
|
|
239
|
+
- **Stored XSS Defenses:** Static file downloads (`/file/:fileId/:safeName`) enforce defense-in-depth security headers:
|
|
240
|
+
- `X-Content-Type-Options: nosniff`
|
|
241
|
+
- `Content-Disposition: attachment` (forces browser download instead of inline execution)
|
|
242
|
+
- `Content-Security-Policy: default-src 'none'; sandbox` (strips script execution privileges and isolates origin)
|
|
243
|
+
- `dotfiles: 'deny'` and `index: false`
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## ๐ ๏ธ Module Exports
|
|
248
|
+
|
|
249
|
+
| Submodule | Purpose |
|
|
250
|
+
| -------------------- | ---------------------------------------------------------------------------------------------- |
|
|
251
|
+
| `Platform` | Primary orchestrator managing endpoints, apps, and user session lifecycles. |
|
|
252
|
+
| `Endpoint` | Express + `express-ws` HTTP/WebSocket server handling auth, sessions, 2FA, and upload streams. |
|
|
253
|
+
| `AgentController` | Spawns and supervises isolated worker threads with `MessageChannel` IPC. |
|
|
254
|
+
| `Panel` / `Fragment` | Fluent builder API for dynamic UI layout structures. |
|
|
255
|
+
| `MinioService` | Object storage client for S3/MinIO presigned URLs and file lifecycle operations. |
|
|
256
|
+
| `I18nService` | Type-safe multi-language translation and fallback engine. |
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## ๐งช Testing
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
# Run unit tests
|
|
264
|
+
npm test
|
|
265
|
+
|
|
266
|
+
# Run tests with built-in code coverage report
|
|
267
|
+
npm run test:coverage
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## ๐ค Author
|
|
273
|
+
|
|
274
|
+
**Amin Abbasi**
|
|
275
|
+
|
|
276
|
+
- Organization: [araminix](https://github.com/araminix)
|
|
277
|
+
- GitHub: [@abbasi](https://github.com)
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
## ๐ License
|
|
282
|
+
|
|
283
|
+
This project is licensed under the **MIT License** - see the [LICENSE](LICENSE) file for details.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import Fragment from './src/builder/Fragment.js';
|
|
2
|
+
import panel from './src/builder/Panel.js';
|
|
3
|
+
import Platform, { UserInstance } from './src/Platform.js';
|
|
4
|
+
import { ConnectRequest } from './src/server/ConnectRequest.js';
|
|
5
|
+
import Endpoint from './src/server/Endpoint.js';
|
|
6
|
+
export * from '@araminix/lib';
|
|
7
|
+
export * from './src/server/index.js';
|
|
8
|
+
export * from './src/utils/index.js';
|
|
9
|
+
export * from './src/lib/d.js';
|
|
10
|
+
export * from './src/lib/actors.js';
|
|
11
|
+
export * from './src/lib/worker_socket.js';
|
|
12
|
+
export * from './src/agent/d.js';
|
|
13
|
+
export * from './src/executor/index.js';
|
|
14
|
+
export { Platform, Endpoint, ConnectRequest, Fragment, panel, UserInstance };
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,2BAA2B,CAAC;AACjD,OAAO,KAAK,MAAM,wBAAwB,CAAC;AAC3C,OAAO,QAAQ,EAAE,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,QAAQ,MAAM,0BAA0B,CAAC;AAEhD,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AAExC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,cAAc,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import Fragment from './src/builder/Fragment.js';
|
|
2
|
+
import panel from './src/builder/Panel.js';
|
|
3
|
+
import Platform from './src/Platform.js';
|
|
4
|
+
import { ConnectRequest } from './src/server/ConnectRequest.js';
|
|
5
|
+
import Endpoint from './src/server/Endpoint.js';
|
|
6
|
+
export * from '@araminix/lib';
|
|
7
|
+
export * from './src/server/index.js';
|
|
8
|
+
export * from './src/utils/index.js';
|
|
9
|
+
export * from './src/lib/d.js';
|
|
10
|
+
export * from './src/lib/actors.js';
|
|
11
|
+
export * from './src/lib/worker_socket.js';
|
|
12
|
+
export * from './src/agent/d.js';
|
|
13
|
+
export * from './src/executor/index.js';
|
|
14
|
+
export { Platform, Endpoint, ConnectRequest, Fragment, panel };
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,2BAA2B,CAAC;AACjD,OAAO,KAAK,MAAM,wBAAwB,CAAC;AAC3C,OAAO,QAA0B,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,QAAQ,MAAM,0BAA0B,CAAC;AAEhD,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AAExC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,cAAc,EAAE,QAAQ,EAAE,KAAK,EAAgB,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Result, Socket, Stream } from '@araminix/lib';
|
|
2
|
+
import { ResourceLimits } from 'worker_threads';
|
|
3
|
+
import Instance from './executor/Instance.js';
|
|
4
|
+
import { AppListing } from './lib/d.js';
|
|
5
|
+
import { AuthProvider, ClientInfo } from './server/AuthProvider.js';
|
|
6
|
+
import Endpoint, { MinioOptions, RateLimitConfig, UploadAllowlist } from './server/Endpoint.js';
|
|
7
|
+
export interface PlatformConfig {
|
|
8
|
+
appIndexPath: URL;
|
|
9
|
+
agentIndexPath: URL;
|
|
10
|
+
authProvider: AuthProvider;
|
|
11
|
+
instanceUserLimit: number;
|
|
12
|
+
maxInstances?: number;
|
|
13
|
+
resourceLimits?: ResourceLimits;
|
|
14
|
+
port?: number;
|
|
15
|
+
mount?: string;
|
|
16
|
+
cookieSecret?: string;
|
|
17
|
+
tabLimit?: number;
|
|
18
|
+
uploadDir?: string;
|
|
19
|
+
maxUploadBytes?: number;
|
|
20
|
+
uploadAllowlist?: UploadAllowlist;
|
|
21
|
+
googleClientIds?: string[];
|
|
22
|
+
allowedOrigins?: string[];
|
|
23
|
+
authRateLimit?: RateLimitConfig | boolean;
|
|
24
|
+
minio?: MinioOptions;
|
|
25
|
+
onCustomStream?: {
|
|
26
|
+
[key: string]: (client: ClientInfo, stream: Stream) => Promise<void>;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export type UserInstance = {
|
|
30
|
+
id: string;
|
|
31
|
+
appName: string;
|
|
32
|
+
appTitle: string;
|
|
33
|
+
activityTitle?: string;
|
|
34
|
+
profile: string | null;
|
|
35
|
+
touched: number;
|
|
36
|
+
};
|
|
37
|
+
export default class Platform {
|
|
38
|
+
private readonly config;
|
|
39
|
+
readonly endpoint: Endpoint;
|
|
40
|
+
private appIndex;
|
|
41
|
+
private agentController;
|
|
42
|
+
readonly instances: Map<string, Map<string, Instance>>;
|
|
43
|
+
get totalInstances(): number;
|
|
44
|
+
constructor(config: PlatformConfig);
|
|
45
|
+
private serve;
|
|
46
|
+
private processInstanceCloseStream;
|
|
47
|
+
processCustomStreams(clientInfo: ClientInfo, endpointSocket: Socket): void;
|
|
48
|
+
private sanitizeClientInfo;
|
|
49
|
+
processUserInfo(clientInfo: ClientInfo, endpointSocket: Socket): void;
|
|
50
|
+
listUserInstances(runtimeId: string): Promise<Array<UserInstance>>;
|
|
51
|
+
listUserApps(userId: string): Promise<Result<Array<AppListing>, void>>;
|
|
52
|
+
private processInstanceListStream;
|
|
53
|
+
private processInstanceStream;
|
|
54
|
+
private processAppsListStream;
|
|
55
|
+
private serveInstance;
|
|
56
|
+
start(): Promise<void>;
|
|
57
|
+
stop(): void;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=Platform.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Platform.d.ts","sourceRoot":"","sources":["../../src/Platform.ts"],"names":[],"mappings":"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"}
|