elit 3.1.6 → 3.1.8
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/build.d.mts +3 -1
- package/dist/cli.js +442 -218
- package/dist/database.d.mts +31 -0
- package/dist/database.d.ts +30 -0
- package/dist/database.d.ts.map +1 -0
- package/dist/database.js +440 -0
- package/dist/database.mjs +406 -0
- package/dist/hmr.d.ts.map +1 -1
- package/dist/hmr.js +4 -5
- package/dist/hmr.mjs +4 -5
- package/dist/http.d.mts +3 -0
- package/dist/http.d.ts +3 -0
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +23 -0
- package/dist/http.mjs +23 -0
- package/dist/https.js +23 -0
- package/dist/https.mjs +23 -0
- package/dist/index.js +4 -5
- package/dist/index.mjs +4 -5
- package/dist/{server-CkRUWELa.d.ts → server-BFOHbYb6.d.ts} +32 -14
- package/dist/{server-D8ktU14v.d.mts → server-BPVoq5Xi.d.mts} +32 -14
- package/dist/server.d.mts +3 -1
- package/dist/server.d.ts +28 -13
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +431 -234
- package/dist/server.mjs +429 -234
- package/dist/types.d.mts +35 -13
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/wss.js +23 -0
- package/dist/wss.mjs +23 -0
- package/package.json +8 -2
- package/src/cli.ts +2 -1
- package/src/database.ts +246 -0
- package/src/hmr.ts +7 -6
- package/src/http.ts +26 -0
- package/src/server.ts +90 -65
- package/src/types.ts +7 -0
package/src/server.ts
CHANGED
|
@@ -16,23 +16,30 @@ import { lookup } from './mime-types';
|
|
|
16
16
|
import { isBun, isDeno } from './runtime';
|
|
17
17
|
import type { DevServerOptions, DevServer, HMRMessage, Child, VNode, ProxyConfig } from './types';
|
|
18
18
|
import { dom } from './dom';
|
|
19
|
+
import { Database, DatabaseConfig } from './database';
|
|
19
20
|
|
|
20
21
|
// ===== Router =====
|
|
21
22
|
|
|
22
23
|
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'OPTIONS' | 'HEAD' | 'ALL';
|
|
23
24
|
|
|
25
|
+
export interface ElitRequest extends IncomingMessage {
|
|
26
|
+
body?: any;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface ElitResponse extends ServerResponse {
|
|
30
|
+
json(data: any, statusCode?: number): this;
|
|
31
|
+
send(data: any): this;
|
|
32
|
+
status(code: number): this;
|
|
33
|
+
}
|
|
34
|
+
|
|
24
35
|
export interface ServerRouteContext {
|
|
25
|
-
req:
|
|
26
|
-
res:
|
|
36
|
+
req: ElitRequest;
|
|
37
|
+
res: ElitResponse;
|
|
27
38
|
params: Record<string, string>;
|
|
28
39
|
query: Record<string, string>;
|
|
29
40
|
body: any;
|
|
30
41
|
headers: Record<string, string | string[] | undefined>;
|
|
31
42
|
user?: any;
|
|
32
|
-
// Express-compatible response helpers
|
|
33
|
-
send?(data: any): ServerResponse;
|
|
34
|
-
json?(data: any): ServerResponse;
|
|
35
|
-
status?(code: number): ServerResponse;
|
|
36
43
|
}
|
|
37
44
|
|
|
38
45
|
export type ServerRouteHandler = (ctx: ServerRouteContext, next?: () => Promise<void>) => void | Promise<void>;
|
|
@@ -46,6 +53,25 @@ interface ServerRoute {
|
|
|
46
53
|
middlewares: Middleware[];
|
|
47
54
|
}
|
|
48
55
|
|
|
56
|
+
class ServerDatabase {
|
|
57
|
+
private _db: Database | null = null;
|
|
58
|
+
|
|
59
|
+
constructor() {
|
|
60
|
+
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async initialize(config: DatabaseConfig) {
|
|
64
|
+
this._db = new Database(config);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
database() {
|
|
68
|
+
return this._db;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export const serverDatabase = new ServerDatabase();
|
|
73
|
+
|
|
74
|
+
export const database = serverDatabase.database;
|
|
49
75
|
export class ServerRouter {
|
|
50
76
|
private routes: ServerRoute[] = [];
|
|
51
77
|
private middlewares: Middleware[] = [];
|
|
@@ -66,19 +92,19 @@ export class ServerRouter {
|
|
|
66
92
|
}
|
|
67
93
|
|
|
68
94
|
// Express-like .all() method - matches all HTTP methods
|
|
69
|
-
all = (path: string, ...handlers: Array<Middleware | ServerRouteHandler | ((req:
|
|
95
|
+
all = (path: string, ...handlers: Array<Middleware | ServerRouteHandler | ((req: ElitRequest, res: ServerResponse, next?: () => void) => any)>): this => this.addRoute('ALL', path, handlers as any);
|
|
70
96
|
|
|
71
97
|
// Support per-route middleware: accept middleware(s) before the final handler
|
|
72
|
-
get = (path: string, ...handlers: Array<Middleware | ServerRouteHandler | ((req:
|
|
73
|
-
post = (path: string, ...handlers: Array<Middleware | ServerRouteHandler | ((req:
|
|
74
|
-
put = (path: string, ...handlers: Array<Middleware | ServerRouteHandler | ((req:
|
|
75
|
-
delete = (path: string, ...handlers: Array<Middleware | ServerRouteHandler | ((req:
|
|
76
|
-
patch = (path: string, ...handlers: Array<Middleware | ServerRouteHandler | ((req:
|
|
77
|
-
options = (path: string, ...handlers: Array<Middleware | ServerRouteHandler | ((req:
|
|
78
|
-
head = (path: string, ...handlers: Array<Middleware | ServerRouteHandler | ((req:
|
|
98
|
+
get = (path: string, ...handlers: Array<Middleware | ServerRouteHandler | ((req: ElitRequest, res: ServerResponse, next?: () => void) => any)>): this => this.addRoute('GET', path, handlers as any);
|
|
99
|
+
post = (path: string, ...handlers: Array<Middleware | ServerRouteHandler | ((req: ElitRequest, res: ServerResponse, next?: () => void) => any)>): this => this.addRoute('POST', path, handlers as any);
|
|
100
|
+
put = (path: string, ...handlers: Array<Middleware | ServerRouteHandler | ((req: ElitRequest, res: ServerResponse, next?: () => void) => any)>): this => this.addRoute('PUT', path, handlers as any);
|
|
101
|
+
delete = (path: string, ...handlers: Array<Middleware | ServerRouteHandler | ((req: ElitRequest, res: ServerResponse, next?: () => void) => any)>): this => this.addRoute('DELETE', path, handlers as any);
|
|
102
|
+
patch = (path: string, ...handlers: Array<Middleware | ServerRouteHandler | ((req: ElitRequest, res: ServerResponse, next?: () => void) => any)>): this => this.addRoute('PATCH', path, handlers as any);
|
|
103
|
+
options = (path: string, ...handlers: Array<Middleware | ServerRouteHandler | ((req: ElitRequest, res: ServerResponse, next?: () => void) => any)>): this => this.addRoute('OPTIONS', path, handlers as any);
|
|
104
|
+
head = (path: string, ...handlers: Array<Middleware | ServerRouteHandler | ((req: ElitRequest, res: ServerResponse, next?: () => void) => any)>): this => this.addRoute('HEAD', path, handlers as any);
|
|
79
105
|
|
|
80
106
|
// Convert Express-like handler/middleware to internal Middleware
|
|
81
|
-
private toMiddleware(fn: Middleware | ServerRouteHandler | ((req:
|
|
107
|
+
private toMiddleware(fn: Middleware | ServerRouteHandler | ((req: ElitRequest, res: ServerResponse, next?: () => void) => any)): Middleware {
|
|
82
108
|
// If it's already our Middleware, return as-is
|
|
83
109
|
if ((fn as Middleware).length === 2 && (fn as any).name !== 'bound ') {
|
|
84
110
|
// Cannot reliably detect, so always wrap to normalize behavior
|
|
@@ -116,7 +142,7 @@ export class ServerRouter {
|
|
|
116
142
|
};
|
|
117
143
|
}
|
|
118
144
|
|
|
119
|
-
private addRoute(method: HttpMethod, path: string, handlers: Array<Middleware | ServerRouteHandler | ((req:
|
|
145
|
+
private addRoute(method: HttpMethod, path: string, handlers: Array<Middleware | ServerRouteHandler | ((req: ElitRequest, res: ServerResponse, next?: () => void) => any)>): this {
|
|
120
146
|
const { pattern, paramNames } = this.pathToRegex(path);
|
|
121
147
|
// Last item is the actual route handler, preceding items are middlewares
|
|
122
148
|
if (!handlers || handlers.length === 0) throw new Error('Route must include a handler');
|
|
@@ -173,10 +199,10 @@ export class ServerRouter {
|
|
|
173
199
|
try {
|
|
174
200
|
const text = await (req as any).text();
|
|
175
201
|
if (!text) return {};
|
|
176
|
-
|
|
202
|
+
|
|
177
203
|
const contentType = req.headers['content-type'];
|
|
178
204
|
const ct = (Array.isArray(contentType) ? contentType[0] : (contentType || '')).toLowerCase();
|
|
179
|
-
|
|
205
|
+
|
|
180
206
|
// Parse JSON (either by content-type or if it looks like JSON)
|
|
181
207
|
if (ct.includes('application/json') || ct.includes('json') || text.trim().startsWith('{') || text.trim().startsWith('[')) {
|
|
182
208
|
try {
|
|
@@ -185,12 +211,12 @@ export class ServerRouter {
|
|
|
185
211
|
return text;
|
|
186
212
|
}
|
|
187
213
|
}
|
|
188
|
-
|
|
214
|
+
|
|
189
215
|
// Parse URL-encoded
|
|
190
216
|
if (ct.includes('application/x-www-form-urlencoded') || ct.includes('urlencoded')) {
|
|
191
217
|
return Object.fromEntries(new URLSearchParams(text));
|
|
192
218
|
}
|
|
193
|
-
|
|
219
|
+
|
|
194
220
|
// Return raw text
|
|
195
221
|
return text;
|
|
196
222
|
} catch (e) {
|
|
@@ -203,28 +229,28 @@ export class ServerRouter {
|
|
|
203
229
|
return new Promise((resolve, reject) => {
|
|
204
230
|
const contentLengthHeader = req.headers['content-length'];
|
|
205
231
|
const contentLength = parseInt(Array.isArray(contentLengthHeader) ? contentLengthHeader[0] : (contentLengthHeader || '0'), 10);
|
|
206
|
-
|
|
232
|
+
|
|
207
233
|
if (contentLength === 0) {
|
|
208
234
|
resolve({});
|
|
209
235
|
return;
|
|
210
236
|
}
|
|
211
237
|
|
|
212
238
|
const chunks: Buffer[] = [];
|
|
213
|
-
|
|
239
|
+
|
|
214
240
|
req.on('data', chunk => {
|
|
215
241
|
chunks.push(Buffer.from(chunk));
|
|
216
242
|
});
|
|
217
|
-
|
|
243
|
+
|
|
218
244
|
req.on('end', () => {
|
|
219
245
|
const body = Buffer.concat(chunks).toString();
|
|
220
246
|
try {
|
|
221
247
|
const ct = req.headers['content-type'] || '';
|
|
222
248
|
resolve(ct.includes('json') ? (body ? JSON.parse(body) : {}) : ct.includes('urlencoded') ? Object.fromEntries(new URLSearchParams(body)) : body);
|
|
223
|
-
} catch (e) {
|
|
224
|
-
reject(e);
|
|
249
|
+
} catch (e) {
|
|
250
|
+
reject(e);
|
|
225
251
|
}
|
|
226
252
|
});
|
|
227
|
-
|
|
253
|
+
|
|
228
254
|
req.on('error', reject);
|
|
229
255
|
});
|
|
230
256
|
}
|
|
@@ -240,48 +266,26 @@ export class ServerRouter {
|
|
|
240
266
|
|
|
241
267
|
let body: any = {};
|
|
242
268
|
if (['POST', 'PUT', 'PATCH'].includes(method)) {
|
|
243
|
-
try {
|
|
269
|
+
try {
|
|
244
270
|
body = await this.parseBody(req);
|
|
271
|
+
// Attach body to req for Express-like compatibility
|
|
272
|
+
(req as ElitRequest).body = body;
|
|
245
273
|
}
|
|
246
|
-
catch (e) {
|
|
247
|
-
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
248
|
-
res.end('{"error":"Invalid request body"}');
|
|
249
|
-
return true;
|
|
274
|
+
catch (e) {
|
|
275
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
276
|
+
res.end('{"error":"Invalid request body"}');
|
|
277
|
+
return true;
|
|
250
278
|
}
|
|
251
279
|
}
|
|
252
280
|
|
|
253
281
|
// Add Express-like response helpers to context
|
|
254
|
-
const ctx: ServerRouteContext = {
|
|
255
|
-
req,
|
|
256
|
-
res,
|
|
257
|
-
params,
|
|
258
|
-
query: this.parseQuery(url),
|
|
259
|
-
body,
|
|
260
|
-
headers: req.headers as any
|
|
261
|
-
send: (data: any) => {
|
|
262
|
-
if (!res.headersSent) {
|
|
263
|
-
if (typeof data === 'object') {
|
|
264
|
-
res.setHeader('Content-Type', 'application/json');
|
|
265
|
-
res.end(JSON.stringify(data));
|
|
266
|
-
} else {
|
|
267
|
-
res.end(String(data));
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
return res;
|
|
271
|
-
},
|
|
272
|
-
json: (data: any) => {
|
|
273
|
-
if (!res.headersSent) {
|
|
274
|
-
res.setHeader('Content-Type', 'application/json');
|
|
275
|
-
res.end(JSON.stringify(data));
|
|
276
|
-
}
|
|
277
|
-
return res;
|
|
278
|
-
},
|
|
279
|
-
status: (code: number) => {
|
|
280
|
-
if (!res.headersSent) {
|
|
281
|
-
res.statusCode = code;
|
|
282
|
-
}
|
|
283
|
-
return res;
|
|
284
|
-
}
|
|
282
|
+
const ctx: ServerRouteContext = {
|
|
283
|
+
req: req as ElitRequest,
|
|
284
|
+
res: res as ElitResponse,
|
|
285
|
+
params,
|
|
286
|
+
query: this.parseQuery(url),
|
|
287
|
+
body,
|
|
288
|
+
headers: req.headers as any
|
|
285
289
|
};
|
|
286
290
|
|
|
287
291
|
// Build middleware chain: global middlewares -> route middlewares -> final handler
|
|
@@ -300,8 +304,8 @@ export class ServerRouter {
|
|
|
300
304
|
await mw(ctx, next);
|
|
301
305
|
};
|
|
302
306
|
|
|
303
|
-
try {
|
|
304
|
-
await next();
|
|
307
|
+
try {
|
|
308
|
+
await next();
|
|
305
309
|
}
|
|
306
310
|
catch (e) {
|
|
307
311
|
console.error('[ServerRouter] Route error:', e);
|
|
@@ -1074,7 +1078,7 @@ export class StateManager {
|
|
|
1074
1078
|
|
|
1075
1079
|
// ===== Development Server =====
|
|
1076
1080
|
|
|
1077
|
-
const defaultOptions: Omit<Required<DevServerOptions>, 'api' | 'clients' | 'root' | 'basePath' | 'ssr' | 'proxy' | 'index' | 'env'> = {
|
|
1081
|
+
const defaultOptions: Omit<Required<DevServerOptions>, 'api' | 'clients' | 'root' | 'basePath' | 'ssr' | 'proxy' | 'index' | 'env' | 'domain' | 'database'> = {
|
|
1078
1082
|
port: 3000,
|
|
1079
1083
|
host: 'localhost',
|
|
1080
1084
|
https: false,
|
|
@@ -1106,6 +1110,14 @@ export function createDevServer(options: DevServerOptions): DevServer {
|
|
|
1106
1110
|
clearImportMapCache();
|
|
1107
1111
|
}
|
|
1108
1112
|
|
|
1113
|
+
// Initialize database connections if provided
|
|
1114
|
+
serverDatabase.initialize(config.database ? config.database : {
|
|
1115
|
+
dir: resolve(process.cwd(), 'databases')
|
|
1116
|
+
})
|
|
1117
|
+
|
|
1118
|
+
|
|
1119
|
+
|
|
1120
|
+
|
|
1109
1121
|
// Normalize clients configuration - support both new API (clients array) and legacy API (root/basePath)
|
|
1110
1122
|
const clientsToNormalize = config.clients?.length ? config.clients : config.root ? [{ root: config.root, basePath: config.basePath || '', index: config.index, ssr: config.ssr, api: config.api, proxy: config.proxy, mode: config.mode }] : null;
|
|
1111
1123
|
if (!clientsToNormalize) throw new Error('DevServerOptions must include either "clients" array or "root" directory');
|
|
@@ -1146,6 +1158,19 @@ export function createDevServer(options: DevServerOptions): DevServer {
|
|
|
1146
1158
|
// HTTP Server
|
|
1147
1159
|
const server = createServer(async (req: IncomingMessage, res: ServerResponse) => {
|
|
1148
1160
|
const originalUrl = req.url || '/';
|
|
1161
|
+
const hostHeader = req.headers.host;
|
|
1162
|
+
const hostName = hostHeader ? (Array.isArray(hostHeader) ? hostHeader[0] : hostHeader).split(':')[0] : '';
|
|
1163
|
+
|
|
1164
|
+
// Handle domain mapping: redirect localhost:port to configured domain
|
|
1165
|
+
if (config.domain && hostName === (config.host || 'localhost')) {
|
|
1166
|
+
const redirectUrl = `http://${config.domain}${originalUrl}`;
|
|
1167
|
+
if (config.logging) {
|
|
1168
|
+
console.log(`[Domain Map] ${hostName}:${config.port}${originalUrl} -> ${redirectUrl}`);
|
|
1169
|
+
}
|
|
1170
|
+
res.writeHead(302, { Location: redirectUrl });
|
|
1171
|
+
res.end();
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
1149
1174
|
|
|
1150
1175
|
// Find matching client based on basePath
|
|
1151
1176
|
const matchedClient = normalizedClients.find(c => c.basePath && originalUrl.startsWith(c.basePath)) || normalizedClients.find(c => !c.basePath);
|
package/src/types.ts
CHANGED
|
@@ -72,6 +72,7 @@ export type ElementFactory = {
|
|
|
72
72
|
|
|
73
73
|
import type { Server } from 'http';
|
|
74
74
|
import type { WebSocketServer } from 'ws';
|
|
75
|
+
import { DatabaseConfig } from './database';
|
|
75
76
|
|
|
76
77
|
// Forward declarations to avoid circular dependency
|
|
77
78
|
export type Router = import('./server').ServerRouter;
|
|
@@ -129,6 +130,8 @@ export interface DevServerOptions {
|
|
|
129
130
|
port?: number;
|
|
130
131
|
/** Host to bind to (default: 'localhost') */
|
|
131
132
|
host?: string;
|
|
133
|
+
/** Domain to map (e.g., 'idevcoder.com') - redirects domain traffic to this server's port */
|
|
134
|
+
domain?: string;
|
|
132
135
|
/** Root directory to serve files from */
|
|
133
136
|
root?: string;
|
|
134
137
|
/** Base path for the client application (e.g., '/app1', '/app2') */
|
|
@@ -159,6 +162,8 @@ export interface DevServerOptions {
|
|
|
159
162
|
mode?: 'dev' | 'preview';
|
|
160
163
|
/** Environment variables to inject (prefix with VITE_ for client access) */
|
|
161
164
|
env?: Record<string, string>;
|
|
165
|
+
/** List of database directories to load */
|
|
166
|
+
database?: DatabaseConfig;
|
|
162
167
|
}
|
|
163
168
|
|
|
164
169
|
export interface DevServer {
|
|
@@ -239,6 +244,8 @@ export interface PreviewOptions {
|
|
|
239
244
|
port?: number;
|
|
240
245
|
/** Host to bind to (default: 'localhost') */
|
|
241
246
|
host?: string;
|
|
247
|
+
/** Domain to map (e.g., 'idevcoder.com') - redirects domain traffic to this server's port */
|
|
248
|
+
domain?: string;
|
|
242
249
|
/** Root directory to serve files from (default: dist or build.outDir) */
|
|
243
250
|
root?: string;
|
|
244
251
|
/** Base path for the application (e.g., '/app') */
|