@mostajs/net 1.0.0-alpha.1 → 1.0.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/README.md +197 -0
- package/dist/cli.js +0 -0
- package/dist/server.js +39 -1
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# MostaNet
|
|
2
|
+
|
|
3
|
+
> **Multi-protocol transport layer for @mostajs/orm** — expose your entities via 11+ protocols.
|
|
4
|
+
> REST, GraphQL, WebSocket, SSE, JSON-RPC, MCP, and more.
|
|
5
|
+
|
|
6
|
+
[](https://www.npmjs.com/package/@mostajs/net)
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## What is MostaNet?
|
|
12
|
+
|
|
13
|
+
MostaNet mirrors the **IDialect adapter pattern** of @mostajs/orm for the transport layer. Where ORM dialects abstract *where* data is stored (13 databases), transport adapters abstract *how* data is exposed (11+ protocols).
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
Client request → ITransport → OrmRequest → EntityService → IDialect → Database
|
|
17
|
+
↓
|
|
18
|
+
OrmResponse → ITransport → Client response
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
One `EntitySchema`, 13 databases, 11+ protocols = **143+ combinations**.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Features
|
|
26
|
+
|
|
27
|
+
- **6 transports implemented** — REST, GraphQL, WebSocket, SSE, JSON-RPC, MCP
|
|
28
|
+
- **5 planned** — gRPC, tRPC, OData, NATS, Arrow Flight
|
|
29
|
+
- **API Key management** — generate, revoke, validate with 3D permission matrix (key x SGBD x protocol)
|
|
30
|
+
- **Middleware pipeline** — logging, auth, rate-limiting, CORS
|
|
31
|
+
- **CLI** — `npx @mostajs/net serve` to start the server
|
|
32
|
+
- **Fastify-based** — high-performance HTTP server
|
|
33
|
+
- **MCP transport** — AI agents (Claude, GPT) can query any database via MCP protocol
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm install @mostajs/orm @mostajs/net
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 1. Define schemas
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
// schemas/user.ts
|
|
47
|
+
import type { EntitySchema } from '@mostajs/orm'
|
|
48
|
+
|
|
49
|
+
export const UserSchema: EntitySchema = {
|
|
50
|
+
name: 'User',
|
|
51
|
+
collection: 'users',
|
|
52
|
+
fields: {
|
|
53
|
+
name: { type: 'string', required: true },
|
|
54
|
+
email: { type: 'string', required: true, unique: true },
|
|
55
|
+
role: { type: 'string', default: 'user' },
|
|
56
|
+
},
|
|
57
|
+
relations: {},
|
|
58
|
+
indexes: [{ fields: { email: 'asc' }, unique: true }],
|
|
59
|
+
timestamps: true,
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 2. Configure .env.local
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# Database
|
|
67
|
+
DB_DIALECT=postgres
|
|
68
|
+
SGBD_URI=postgresql://user:pass@localhost:5432/mydb
|
|
69
|
+
DB_SCHEMA_STRATEGY=update
|
|
70
|
+
|
|
71
|
+
# Transports
|
|
72
|
+
MOSTA_NET_REST_ENABLED=true
|
|
73
|
+
MOSTA_NET_REST_PORT=3000
|
|
74
|
+
MOSTA_NET_GRAPHQL_ENABLED=true
|
|
75
|
+
MOSTA_NET_WS_ENABLED=true
|
|
76
|
+
MOSTA_NET_SSE_ENABLED=true
|
|
77
|
+
MOSTA_NET_JSONRPC_ENABLED=true
|
|
78
|
+
MOSTA_NET_MCP_ENABLED=true
|
|
79
|
+
|
|
80
|
+
# Logging (from @mostajs/orm)
|
|
81
|
+
DB_SHOW_SQL=true
|
|
82
|
+
DB_FORMAT_SQL=true
|
|
83
|
+
DB_HIGHLIGHT_SQL=true
|
|
84
|
+
DB_POOL_SIZE=20
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 3. Start the server
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
npx @mostajs/net serve
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Or programmatically :
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
import { startServer } from '@mostajs/net'
|
|
97
|
+
|
|
98
|
+
await startServer({
|
|
99
|
+
schemas: [UserSchema],
|
|
100
|
+
port: 3000,
|
|
101
|
+
})
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 4. Use it
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# REST
|
|
108
|
+
curl http://localhost:3000/api/v1/users
|
|
109
|
+
curl -X POST http://localhost:3000/api/v1/users -d '{"name":"Dr Madani","email":"drmdh@msn.com"}'
|
|
110
|
+
|
|
111
|
+
# GraphQL
|
|
112
|
+
curl -X POST http://localhost:3000/graphql -d '{"query":"{ users { id name email } }"}'
|
|
113
|
+
|
|
114
|
+
# JSON-RPC
|
|
115
|
+
curl -X POST http://localhost:3000/rpc -d '{"jsonrpc":"2.0","method":"User.findAll","id":1}'
|
|
116
|
+
|
|
117
|
+
# WebSocket
|
|
118
|
+
wscat -c ws://localhost:3000/ws
|
|
119
|
+
> {"op":"findAll","entity":"User"}
|
|
120
|
+
|
|
121
|
+
# MCP (via Claude/GPT agent)
|
|
122
|
+
# Tools: User_findAll, User_create, User_count, etc.
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Transports
|
|
128
|
+
|
|
129
|
+
| Transport | Protocol | Status | Use case |
|
|
130
|
+
|-----------|----------|--------|----------|
|
|
131
|
+
| **RestTransport** | HTTP REST | ✅ Production | Universal API (7 routes per entity) |
|
|
132
|
+
| **GraphQLTransport** | GraphQL | ✅ Production | Flexible queries, auto-generated schema |
|
|
133
|
+
| **WebSocketTransport** | WebSocket | ✅ Production | Bidirectional, real-time |
|
|
134
|
+
| **SSETransport** | Server-Sent Events | ✅ Production | Real-time broadcast (entity.created/updated/deleted) |
|
|
135
|
+
| **JsonRpcTransport** | JSON-RPC 2.0 | ✅ Production | Batch requests, method discovery |
|
|
136
|
+
| **McpTransport** | Model Context Protocol | ✅ Production | AI agents (Claude, GPT, Copilot) |
|
|
137
|
+
| GrpcTransport | gRPC | Planned | Service-to-service |
|
|
138
|
+
| TrpcTransport | tRPC | Planned | End-to-end type safety |
|
|
139
|
+
| ODataTransport | OData | Planned | Enterprise integration |
|
|
140
|
+
| NatsTransport | NATS | Planned | Message queue |
|
|
141
|
+
| ArrowFlightTransport | Arrow Flight | Planned | Analytics, big data |
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## API Key Management
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
# Generate a key
|
|
149
|
+
npx @mostajs/net generate-apikey "My App" live
|
|
150
|
+
|
|
151
|
+
# List keys
|
|
152
|
+
npx @mostajs/net list-keys
|
|
153
|
+
|
|
154
|
+
# Revoke a key
|
|
155
|
+
npx @mostajs/net revoke-key "My App"
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Keys are stored in `.mosta/apikeys.json` with bcrypt hashes and a 3D permission matrix (API key x database x transport x operation).
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Architecture
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
@mostajs/net (this package)
|
|
166
|
+
↓ depends on
|
|
167
|
+
@mostajs/orm (13 databases)
|
|
168
|
+
↓ managed by
|
|
169
|
+
@mostajs/ornetadmin (admin UI)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
- **net depends on orm** (unidirectional)
|
|
173
|
+
- **orm has zero transport dependencies**
|
|
174
|
+
- **ornetadmin writes config files** that orm and net read
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## CLI Commands
|
|
179
|
+
|
|
180
|
+
| Command | Description |
|
|
181
|
+
|---------|-------------|
|
|
182
|
+
| `npx @mostajs/net serve` | Start the transport server |
|
|
183
|
+
| `npx @mostajs/net info` | Show config, transports, API keys |
|
|
184
|
+
| `npx @mostajs/net generate-apikey <name> [live\|test]` | Generate an API key |
|
|
185
|
+
| `npx @mostajs/net list-keys` | List all API keys |
|
|
186
|
+
| `npx @mostajs/net revoke-key <name>` | Revoke an API key |
|
|
187
|
+
| `npx @mostajs/net hash-password <password>` | Hash a password (SHA-256) |
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## License
|
|
192
|
+
|
|
193
|
+
MIT — © 2025-2026 Dr Hamid MADANI <drmdh@msn.com>
|
|
194
|
+
|
|
195
|
+
## Contributing
|
|
196
|
+
|
|
197
|
+
Issues and PRs welcome at [github.com/apolocine/mosta-net](https://github.com/apolocine/mosta-net).
|
package/dist/cli.js
CHANGED
|
File without changes
|
package/dist/server.js
CHANGED
|
@@ -31,8 +31,46 @@ export async function startServer() {
|
|
|
31
31
|
const entityService = new EntityService(dialect);
|
|
32
32
|
// 4. Get schemas
|
|
33
33
|
const schemas = getAllSchemas();
|
|
34
|
-
// 5.
|
|
34
|
+
// 5. Display startup banner
|
|
35
|
+
const C = { reset: '\x1b[0m', dim: '\x1b[2m', cyan: '\x1b[36m', green: '\x1b[32m', yellow: '\x1b[33m', magenta: '\x1b[35m', gray: '\x1b[90m', blue: '\x1b[34m' };
|
|
36
|
+
const maskedUri = (process.env.SGBD_URI || '').replace(/:([^@]+)@/, ':***@');
|
|
37
|
+
console.log(`
|
|
38
|
+
${C.cyan}┌─────────────────────────────────────────────────────┐${C.reset}
|
|
39
|
+
${C.cyan}│${C.reset} ${C.cyan}@mostajs/net${C.reset} ${C.cyan}│${C.reset}
|
|
40
|
+
${C.cyan}│${C.reset} Dialect: ${C.green}${process.env.DB_DIALECT || 'unknown'}${C.reset} ${C.dim}(${maskedUri})${C.reset}
|
|
41
|
+
${C.cyan}│${C.reset} Entities: ${C.green}${schemas.map(s => s.name).join(', ')}${C.reset} ${C.dim}(${schemas.length})${C.reset}
|
|
42
|
+
${C.cyan}│${C.reset} Port: ${C.yellow}${config.port}${C.reset}
|
|
43
|
+
${C.cyan}│${C.reset} Show SQL: ${process.env.DB_SHOW_SQL === 'true' ? C.green + 'true' : C.gray + 'false'}${C.reset} Format: ${process.env.DB_FORMAT_SQL === 'true' ? C.green + 'true' : C.gray + 'false'}${C.reset} Highlight: ${process.env.DB_HIGHLIGHT_SQL === 'true' ? C.green + 'true' : C.gray + 'false'}${C.reset}
|
|
44
|
+
${C.cyan}│${C.reset} Pool: ${C.yellow}${process.env.DB_POOL_SIZE || '10'}${C.reset} Strategy: ${C.yellow}${process.env.DB_SCHEMA_STRATEGY || 'none'}${C.reset}
|
|
45
|
+
${C.cyan}│${C.reset} Transports: ${C.green}${getEnabledTransports(config).join(', ')}${C.reset} ${C.dim}(${getEnabledTransports(config).length})${C.reset}
|
|
46
|
+
${C.cyan}└─────────────────────────────────────────────────────┘${C.reset}
|
|
47
|
+
`);
|
|
48
|
+
// 5b. Create shared Fastify instance
|
|
35
49
|
const app = Fastify({ logger: false });
|
|
50
|
+
// 5c. Request logger — log each transaction to terminal
|
|
51
|
+
app.addHook('onResponse', (req, reply, done) => {
|
|
52
|
+
const ms = reply.elapsedTime?.toFixed(0) || '?';
|
|
53
|
+
const status = reply.statusCode;
|
|
54
|
+
const method = req.method;
|
|
55
|
+
const url = req.url;
|
|
56
|
+
// Detect transport from URL
|
|
57
|
+
let transport = 'HTTP';
|
|
58
|
+
if (url.startsWith('/api/v1/'))
|
|
59
|
+
transport = 'REST';
|
|
60
|
+
else if (url.startsWith('/graphql'))
|
|
61
|
+
transport = 'GraphQL';
|
|
62
|
+
else if (url.startsWith('/rpc'))
|
|
63
|
+
transport = 'JSON-RPC';
|
|
64
|
+
else if (url.startsWith('/ws'))
|
|
65
|
+
transport = 'WS';
|
|
66
|
+
else if (url.startsWith('/events'))
|
|
67
|
+
transport = 'SSE';
|
|
68
|
+
else if (url.startsWith('/mcp'))
|
|
69
|
+
transport = 'MCP';
|
|
70
|
+
const statusColor = status < 300 ? C.green : status < 400 ? C.yellow : C.magenta;
|
|
71
|
+
console.log(`${C.dim}[NET:${C.cyan}${transport}${C.dim}]${C.reset} ${C.blue}${method}${C.reset} ${url} ${statusColor}${status}${C.reset} ${C.gray}(${ms}ms)${C.reset}`);
|
|
72
|
+
done();
|
|
73
|
+
});
|
|
36
74
|
// 6. ORM handler (OrmRequest → EntityService → OrmResponse)
|
|
37
75
|
const ormHandler = async (req, _ctx) => {
|
|
38
76
|
return entityService.execute(req);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mostajs/net",
|
|
3
|
-
"version": "1.0.0
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Multi-protocol transport layer for @mostajs/orm — expose entities via REST, gRPC, GraphQL, WebSocket, SSE, tRPC, MCP, OData, Arrow Flight, JSON-RPC, NATS",
|
|
5
5
|
"author": "Dr Hamid MADANI <drmdh@msn.com>",
|
|
6
6
|
"license": "MIT",
|