redweb 0.7.2 → 0.7.4

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/index.d.ts CHANGED
@@ -1,173 +1,173 @@
1
- declare module 'redweb' {
2
- import { Application } from 'express';
3
- import { CorsOptions } from 'cors';
4
- import { Server as HttpServer } from 'http';
5
- import { WebSocket } from 'ws';
6
-
7
- /** ─────────────────── HTTP / CORE ─────────────────── */
8
-
9
- export type RedWebEncoding = 'json' | 'urlencoded';
10
-
11
- export interface RedWebOptions {
12
- port?: number;
13
- bind?: string;
14
- publicPaths?: string[];
15
- services?: Array<{ serviceName: string; method: string; function: Function }>;
16
- listenCallback?: () => void;
17
- encoding?: RedWebEncoding;
18
- ssl?: { key: string; cert: string };
19
- server?: Application;
20
- corsOptions?: CorsOptions;
21
- enableHtmxRendering?: boolean;
22
- }
23
-
24
- /** ─────────────────── SOCKET SERVER ─────────────────── */
25
-
26
- export interface SocketServerOptions {
27
- server?: HttpServer;
28
- port?: number;
29
- routes?: Array<new () => SocketRoute>;
30
- ssl?: { key: string; cert: string };
31
- }
32
-
33
- /** ─────────────────── ROUTES & HANDLERS ─────────────────── */
34
-
35
- export interface SocketRouteConfig {
36
- path: string;
37
- handlers: Array<new () => BaseHandler>;
38
- services?: Array<new () => SocketService>;
39
- allowDuplicateConnections?: boolean;
40
- }
41
-
42
- /** Socket‑side autonomous service (game loops, timers, etc.) */
43
- export abstract class SocketService {
44
- name: string;
45
- tickRateMs?: number;
46
- protected _tickHandle?: NodeJS.Timeout;
47
-
48
- constructor(name: string, tickRateMs?: number);
49
-
50
- /** Called once when the route is initialised */
51
- onInit(route: SocketRoute): void;
52
-
53
- /** Optional recurring tick (respecting tickRateMs) */
54
- onTick?(): void;
55
-
56
- /** Called on process shutdown / route removal */
57
- onShutdown(): void;
58
- }
59
-
60
- /** Message handler, triggered by client messages */
61
- export class BaseHandler {
62
- name: string;
63
- constructor(name: string);
64
-
65
- handleMessage(
66
- socket: WebSocket & {
67
- sendJson: (message: object) => void;
68
- broadcast: (message: object) => void;
69
- },
70
- message: any
71
- ): void;
72
-
73
- onMessage(socket: WebSocket, message: any): void;
74
- onInitialContact(socket: WebSocket): void;
75
- }
76
-
77
- export class SocketRoute {
78
- path: string;
79
- handlers: BaseHandler[];
80
- clients: Map<string, WebSocket>;
81
- allowDuplicateConnections?: boolean;
82
-
83
- constructor(config: SocketRouteConfig);
84
-
85
- addHandler(handler: new () => BaseHandler): void;
86
- handleMessage(sock: WebSocket, data: any): void;
87
- }
88
-
89
- /** ─────────────────── SERVER BASE ─────────────────── */
90
-
91
- export class BaseSocketServer {
92
- clients: Map<string, WebSocket>;
93
- server: HttpServer;
94
- routes: SocketRoute[];
95
-
96
- constructor(server: HttpServer, options?: SocketServerOptions);
97
-
98
- addRoute(route: new () => SocketRoute): void;
99
- }
100
-
101
- /** ─────────────────── REGISTRY & UTIL TYPES ─────────────────── */
102
-
103
- export interface SocketWrapper {
104
- socket: WebSocket;
105
- id: string;
106
- send: (type: string, payload: Record<string, any>) => void;
107
- getSanitized?(): Record<string, any>;
108
- }
109
-
110
- export type SocketMessage = {
111
- type: string;
112
- [key: string]: any;
113
- };
114
-
115
- /** Generic event‑driven registry for socket objects */
116
- /** Generic event-driven registry for socket objects */
117
- export class SocketRegistry<T extends SocketWrapper = SocketWrapper> extends EventEmitter {
118
- protected items: T[];
119
-
120
- constructor();
121
-
122
- /** Adds a socket-bound object to the registry */
123
- add(item: T): void;
124
-
125
- /**
126
- * Removes a socket-bound object by reference or id (default key: 'id')
127
- * @param itemOrId Object or ID string
128
- * @param by Key name to match against (default is 'id')
129
- */
130
- remove(itemOrId: T | string, by?: keyof T): boolean;
131
-
132
- /** Returns a shallow copy of all registered items */
133
- all(): T[];
134
-
135
- /** Returns the number of registered items */
136
- count(): number;
137
- }
138
-
139
- /** ─────────────────── CONCRETE SERVERS ─────────────────── */
140
-
141
- export class SocketServer extends BaseSocketServer {
142
- constructor(options?: SocketServerOptions);
143
- }
144
-
145
- export class SecureSocketServer extends BaseSocketServer {
146
- constructor(options?: SocketServerOptions);
147
- }
148
-
149
- export class HttpServer {
150
- constructor(options?: RedWebOptions);
151
- }
152
-
153
- export class HttpsServer {
154
- constructor(options?: RedWebOptions);
155
- }
156
-
157
- /** ─────────────────── CONSTANTS ─────────────────── */
158
-
159
- export const METHODS: {
160
- GET: 'get';
161
- POST: 'post';
162
- PUT: 'put';
163
- DELETE: 'delete';
164
- };
165
-
166
- export const ENCODINGS: {
167
- json: 'json';
168
- urlencoded: 'urlencoded';
169
- };
170
-
171
- export const HTTP_OPTIONS: RedWebOptions;
172
- export const SOCKET_OPTIONS: SocketServerOptions;
173
- }
1
+ declare module 'redweb' {
2
+ import { Application } from 'express';
3
+ import { CorsOptions } from 'cors';
4
+ import { Server as HttpServer } from 'http';
5
+ import { WebSocket } from 'ws';
6
+
7
+ /** ─────────────────── HTTP / CORE ─────────────────── */
8
+
9
+ export type RedWebEncoding = 'json' | 'urlencoded';
10
+
11
+ export interface RedWebOptions {
12
+ port?: number;
13
+ bind?: string;
14
+ publicPaths?: string[];
15
+ services?: Array<{ serviceName: string; method: string; function: Function }>;
16
+ listenCallback?: () => void;
17
+ encoding?: RedWebEncoding;
18
+ ssl?: { key: string; cert: string };
19
+ server?: Application;
20
+ corsOptions?: CorsOptions;
21
+ enableHtmxRendering?: boolean;
22
+ }
23
+
24
+ /** ─────────────────── SOCKET SERVER ─────────────────── */
25
+
26
+ export interface SocketServerOptions {
27
+ server?: HttpServer;
28
+ port?: number;
29
+ routes?: Array<new () => SocketRoute>;
30
+ ssl?: { key: string; cert: string };
31
+ }
32
+
33
+ /** ─────────────────── ROUTES & HANDLERS ─────────────────── */
34
+
35
+ export interface SocketRouteConfig {
36
+ path: string;
37
+ handlers: Array<new () => BaseHandler>;
38
+ services?: Array<new () => SocketService>;
39
+ allowDuplicateConnections?: boolean;
40
+ }
41
+
42
+ /** Socket‑side autonomous service (game loops, timers, etc.) */
43
+ export abstract class SocketService {
44
+ name: string;
45
+ tickRateMs?: number;
46
+ protected _tickHandle?: NodeJS.Timeout;
47
+
48
+ constructor(name: string, tickRateMs?: number);
49
+
50
+ /** Called once when the route is initialised */
51
+ onInit(route: SocketRoute): void;
52
+
53
+ /** Optional recurring tick (respecting tickRateMs) */
54
+ onTick?(): void;
55
+
56
+ /** Called on process shutdown / route removal */
57
+ onShutdown(): void;
58
+ }
59
+
60
+ /** Message handler, triggered by client messages */
61
+ export class BaseHandler {
62
+ name: string;
63
+ constructor(name: string);
64
+
65
+ handleMessage(
66
+ socket: WebSocket & {
67
+ sendJson: (message: object) => void;
68
+ broadcast: (message: object) => void;
69
+ },
70
+ message: any
71
+ ): void;
72
+
73
+ onMessage(socket: WebSocket, message: any): void;
74
+ onInitialContact(socket: WebSocket): void;
75
+ }
76
+
77
+ export class SocketRoute {
78
+ path: string;
79
+ handlers: BaseHandler[];
80
+ clients: Map<string, WebSocket>;
81
+ allowDuplicateConnections?: boolean;
82
+
83
+ constructor(config: SocketRouteConfig);
84
+
85
+ addHandler(handler: new () => BaseHandler): void;
86
+ handleMessage(sock: WebSocket, data: any): void;
87
+ }
88
+
89
+ /** ─────────────────── SERVER BASE ─────────────────── */
90
+
91
+ export class BaseSocketServer {
92
+ clients: Map<string, WebSocket>;
93
+ server: HttpServer;
94
+ routes: SocketRoute[];
95
+
96
+ constructor(server: HttpServer, options?: SocketServerOptions);
97
+
98
+ addRoute(route: new () => SocketRoute): void;
99
+ }
100
+
101
+ /** ─────────────────── REGISTRY & UTIL TYPES ─────────────────── */
102
+
103
+ export interface SocketWrapper {
104
+ socket: WebSocket;
105
+ id: string;
106
+ send: (type: string, payload: Record<string, any>) => void;
107
+ getSanitized?(): Record<string, any>;
108
+ }
109
+
110
+ export type SocketMessage = {
111
+ type: string;
112
+ [key: string]: any;
113
+ };
114
+
115
+ /** Generic event‑driven registry for socket objects */
116
+ /** Generic event-driven registry for socket objects */
117
+ export class SocketRegistry<T extends SocketWrapper = SocketWrapper> extends EventEmitter {
118
+ protected items: T[];
119
+
120
+ constructor();
121
+
122
+ /** Adds a socket-bound object to the registry */
123
+ add(item: T): void;
124
+
125
+ /**
126
+ * Removes a socket-bound object by reference or id (default key: 'id')
127
+ * @param itemOrId Object or ID string
128
+ * @param by Key name to match against (default is 'id')
129
+ */
130
+ remove(itemOrId: T | string, by?: keyof T): boolean;
131
+
132
+ /** Returns a shallow copy of all registered items */
133
+ all(): T[];
134
+
135
+ /** Returns the number of registered items */
136
+ count(): number;
137
+ }
138
+
139
+ /** ─────────────────── CONCRETE SERVERS ─────────────────── */
140
+
141
+ export class SocketServer extends BaseSocketServer {
142
+ constructor(options?: SocketServerOptions);
143
+ }
144
+
145
+ export class SecureSocketServer extends BaseSocketServer {
146
+ constructor(options?: SocketServerOptions);
147
+ }
148
+
149
+ export class HttpServer {
150
+ constructor(options?: RedWebOptions);
151
+ }
152
+
153
+ export class HttpsServer {
154
+ constructor(options?: RedWebOptions);
155
+ }
156
+
157
+ /** ─────────────────── CONSTANTS ─────────────────── */
158
+
159
+ export const METHODS: {
160
+ GET: 'get';
161
+ POST: 'post';
162
+ PUT: 'put';
163
+ DELETE: 'delete';
164
+ };
165
+
166
+ export const ENCODINGS: {
167
+ json: 'json';
168
+ urlencoded: 'urlencoded';
169
+ };
170
+
171
+ export const HTTP_OPTIONS: RedWebOptions;
172
+ export const SOCKET_OPTIONS: SocketServerOptions;
173
+ }
package/index.js CHANGED
@@ -1,19 +1,19 @@
1
- const { METHODS } = require('./src/http');
2
- const { sendJson } = require('./src/ws/util');
3
- const { SocketServer, SecureSocketServer, SOCKET_OPTIONS, SocketRoute, SocketService, SocketRegistry } = require('./src/ws');
4
- const { BaseHandler } = require('./src/ws/BaseHandler');
5
- const HttpServer = require('./src/http/HttpServer');
6
- const HttpsServer = require('./src/http/HttpsServer');
7
- module.exports = {
8
- HttpServer,
9
- HttpsServer,
10
- SocketServer,
11
- SecureSocketServer,
12
- BaseHandler,
13
- SocketRoute,
14
- SocketService,
15
- SocketRegistry,
16
- sendJson,
17
- SOCKET_OPTIONS,
18
- METHODS
19
- };
1
+ const { METHODS } = require('./src/http');
2
+ const { sendJson } = require('./src/ws/util');
3
+ const { SocketServer, SecureSocketServer, SOCKET_OPTIONS, SocketRoute, SocketService, SocketRegistry } = require('./src/ws');
4
+ const { BaseHandler } = require('./src/ws/BaseHandler');
5
+ const HttpServer = require('./src/http/HttpServer');
6
+ const HttpsServer = require('./src/http/HttpsServer');
7
+ module.exports = {
8
+ HttpServer,
9
+ HttpsServer,
10
+ SocketServer,
11
+ SecureSocketServer,
12
+ BaseHandler,
13
+ SocketRoute,
14
+ SocketService,
15
+ SocketRegistry,
16
+ sendJson,
17
+ SOCKET_OPTIONS,
18
+ METHODS
19
+ };
package/package.json CHANGED
@@ -1,27 +1,27 @@
1
- {
2
- "name": "redweb",
3
- "version": "0.7.2",
4
- "description": "A way to quickly set up an express server",
5
- "main": "index.js",
6
- "scripts": {
7
- "test": "node tester.js"
8
- },
9
- "files": [
10
- "src/*",
11
- "index.d.ts"
12
- ],
13
- "keywords": [],
14
- "author": "",
15
- "license": "ISC",
16
- "dependencies": {
17
- "cors": "^2.8.5",
18
- "express": "^4.19.2",
19
- "ws": "^8.17.0"
20
- },
21
- "devDependencies": {
22
- "@types/express": "^4.17.21",
23
- "@types/jest": "^29.5.12",
24
- "jest": "^29.7.0",
25
- "supertest": "^7.0.0"
26
- }
27
- }
1
+ {
2
+ "name": "redweb",
3
+ "version": "0.7.4",
4
+ "description": "A way to quickly set up an express server",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "npx jest"
8
+ },
9
+ "files": [
10
+ "src/*",
11
+ "index.d.ts"
12
+ ],
13
+ "keywords": [],
14
+ "author": "",
15
+ "license": "ISC",
16
+ "dependencies": {
17
+ "cors": "^2.8.5",
18
+ "express": "^4.19.2",
19
+ "ws": "^8.17.0"
20
+ },
21
+ "devDependencies": {
22
+ "@types/express": "^4.17.21",
23
+ "@types/jest": "^29.5.12",
24
+ "jest": "^29.7.0",
25
+ "supertest": "^7.0.0"
26
+ }
27
+ }
@@ -1,65 +1,65 @@
1
- const fs = require('fs');
2
- const vm = require('vm');
3
- const path = require('path');
4
-
5
- class HtmxRenderer {
6
- /**
7
- * Render an .htmx file as JavaScript with embedded print statements.
8
- * @param {string} filePath - Path to the .htmx file.
9
- * @returns {string} Rendered HTML string with normalized whitespace.
10
- */
11
- static render(filePath) {
12
- if (!fs.existsSync(filePath)) {
13
- throw new Error(`Template file not found: ${filePath}`);
14
- }
15
-
16
- let output = '';
17
- const templateContent = fs.readFileSync(filePath, 'utf-8');
18
-
19
- // Transform <@ ... @/> blocks into print() calls
20
- const transformedTemplate = templateContent.replace(
21
- /<@>([\s\S]*?)<@\/>/g,
22
- (_, content) => `print(\`${content.replace(/{{\s*(.*?)\s*}}/g, '${$1}')}\`);`
23
- );
24
-
25
- // Wrap the script in an IIFE
26
- const wrappedScript = `
27
- (() => {
28
- const print = (html) => output += html;
29
- ${transformedTemplate}
30
- return output;
31
- })();
32
- `;
33
-
34
- // Create a custom require function that resolves paths relative to the template
35
- const customRequire = (modulePath) => {
36
- const absolutePath = path.resolve(path.dirname(filePath), modulePath);
37
- return require(absolutePath);
38
- };
39
-
40
- // Execute the script in a sandbox
41
- const script = new vm.Script(wrappedScript);
42
- const sandbox = {
43
- output: '',
44
- require: customRequire, // Add custom require
45
- __dirname: path.dirname(filePath),
46
- __filename: filePath,
47
- };
48
- vm.createContext(sandbox);
49
-
50
- // Get the rendered output
51
- let result = script.runInContext(sandbox);
52
-
53
- // Normalize spaces but preserve those in content
54
- result = result
55
- .replace(/>\s+</g, '><') // Remove spaces between tags
56
- .replace(/\s+/g, ' ') // Collapse multiple spaces to one
57
- .replace(/>\s+/g, '>') // Remove spaces after tags
58
- .replace(/\s+</g, '<') // Remove spaces before tags
59
- .trim(); // Trim leading and trailing spaces
60
-
61
- return result;
62
- }
63
- }
64
-
65
- module.exports = HtmxRenderer;
1
+ const fs = require('fs');
2
+ const vm = require('vm');
3
+ const path = require('path');
4
+
5
+ class HtmxRenderer {
6
+ /**
7
+ * Render an .htmx file as JavaScript with embedded print statements.
8
+ * @param {string} filePath - Path to the .htmx file.
9
+ * @returns {string} Rendered HTML string with normalized whitespace.
10
+ */
11
+ static render(filePath) {
12
+ if (!fs.existsSync(filePath)) {
13
+ throw new Error(`Template file not found: ${filePath}`);
14
+ }
15
+
16
+ let output = '';
17
+ const templateContent = fs.readFileSync(filePath, 'utf-8');
18
+
19
+ // Transform <@ ... @/> blocks into print() calls
20
+ const transformedTemplate = templateContent.replace(
21
+ /<@>([\s\S]*?)<@\/>/g,
22
+ (_, content) => `print(\`${content.replace(/{{\s*(.*?)\s*}}/g, '${$1}')}\`);`
23
+ );
24
+
25
+ // Wrap the script in an IIFE
26
+ const wrappedScript = `
27
+ (() => {
28
+ const print = (html) => output += html;
29
+ ${transformedTemplate}
30
+ return output;
31
+ })();
32
+ `;
33
+
34
+ // Create a custom require function that resolves paths relative to the template
35
+ const customRequire = (modulePath) => {
36
+ const absolutePath = path.resolve(path.dirname(filePath), modulePath);
37
+ return require(absolutePath);
38
+ };
39
+
40
+ // Execute the script in a sandbox
41
+ const script = new vm.Script(wrappedScript);
42
+ const sandbox = {
43
+ output: '',
44
+ require: customRequire, // Add custom require
45
+ __dirname: path.dirname(filePath),
46
+ __filename: filePath,
47
+ };
48
+ vm.createContext(sandbox);
49
+
50
+ // Get the rendered output
51
+ let result = script.runInContext(sandbox);
52
+
53
+ // Normalize spaces but preserve those in content
54
+ result = result
55
+ .replace(/>\s+</g, '><') // Remove spaces between tags
56
+ .replace(/\s+/g, ' ') // Collapse multiple spaces to one
57
+ .replace(/>\s+/g, '>') // Remove spaces after tags
58
+ .replace(/\s+</g, '<') // Remove spaces before tags
59
+ .trim(); // Trim leading and trailing spaces
60
+
61
+ return result;
62
+ }
63
+ }
64
+
65
+ module.exports = HtmxRenderer;
@@ -1,11 +1,11 @@
1
- class RedWebHtmxComponent {
2
- constructor(props = {}) {
3
- this.props = props;
4
- }
5
-
6
- render() {
7
- throw new Error('Render method must be implemented in derived components');
8
- }
9
- }
10
-
11
- module.exports = RedWebHtmxComponent;
1
+ class RedWebHtmxComponent {
2
+ constructor(props = {}) {
3
+ this.props = props;
4
+ }
5
+
6
+ render() {
7
+ throw new Error('Render method must be implemented in derived components');
8
+ }
9
+ }
10
+
11
+ module.exports = RedWebHtmxComponent;