@coffer-org/plugin-http 1.2.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/dist/index.d.ts +2 -0
- package/dist/index.js +15 -0
- package/dist/runtime/config.d.ts +11 -0
- package/dist/runtime/config.js +15 -0
- package/dist/runtime/connector.d.ts +6 -0
- package/dist/runtime/connector.js +23 -0
- package/dist/runtime/index.d.ts +6 -0
- package/dist/runtime/index.js +16 -0
- package/dist/runtime/server.d.ts +7 -0
- package/dist/runtime/server.js +83 -0
- package/package.json +33 -0
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { definePlugin } from '@coffer-org/sdk/plugin';
|
|
2
|
+
import { defineSettings } from '@coffer-org/sdk/settings';
|
|
3
|
+
import { field } from '@coffer-org/sdk/fields';
|
|
4
|
+
export default definePlugin({
|
|
5
|
+
id: 'http',
|
|
6
|
+
version: '1.0.0',
|
|
7
|
+
dependsOn: ['orchestrator'],
|
|
8
|
+
settings: defineSettings({
|
|
9
|
+
label: 'http.settings.label',
|
|
10
|
+
fields: [
|
|
11
|
+
field.int({ key: 'port', label: 'http.settings.port' }),
|
|
12
|
+
field.password({ key: 'access_password', label: 'http.settings.access_password' }),
|
|
13
|
+
],
|
|
14
|
+
}),
|
|
15
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { GatePolicy } from '@coffer-org/plugin-orchestrator/runtime';
|
|
2
|
+
export interface HttpConfig {
|
|
3
|
+
port: number;
|
|
4
|
+
accessPassword: string;
|
|
5
|
+
}
|
|
6
|
+
export interface LoadOpts {
|
|
7
|
+
env?: Record<string, string | undefined>;
|
|
8
|
+
dbSettings?: Record<string, unknown>;
|
|
9
|
+
}
|
|
10
|
+
export declare function loadHttpConfig(opts?: LoadOpts): HttpConfig;
|
|
11
|
+
export declare function policy(cfg: HttpConfig): GatePolicy;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function loadHttpConfig(opts = {}) {
|
|
2
|
+
const env = opts.env ?? process.env;
|
|
3
|
+
const db = (opts.dbSettings ?? {});
|
|
4
|
+
return {
|
|
5
|
+
port: Number(env['HTTP_CONNECTOR_PORT'] ?? db['port'] ?? 7025) || 7025,
|
|
6
|
+
accessPassword: env['HTTP_CONNECTOR_PASSWORD'] ?? db['access_password'] ?? '',
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export function policy(cfg) {
|
|
10
|
+
return {
|
|
11
|
+
accessPassword: cfg.accessPassword,
|
|
12
|
+
triggerPrefix: '',
|
|
13
|
+
replyWindow: 1800,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export function makeBufferedConnector() {
|
|
2
|
+
const buffer = [];
|
|
3
|
+
let counter = 0;
|
|
4
|
+
const capabilities = {
|
|
5
|
+
streaming: false,
|
|
6
|
+
typing: false,
|
|
7
|
+
maxMessageLength: 100_000,
|
|
8
|
+
};
|
|
9
|
+
const connector = {
|
|
10
|
+
id: 'http',
|
|
11
|
+
capabilities,
|
|
12
|
+
async sendMessage(_chatId, text) {
|
|
13
|
+
buffer.push(text);
|
|
14
|
+
return { msgId: String(counter++) };
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
return {
|
|
18
|
+
connector,
|
|
19
|
+
drain() {
|
|
20
|
+
return buffer.splice(0);
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { PluginHooks } from '@coffer-org/server/plugin-hooks';
|
|
2
|
+
export type { HttpConfig, LoadOpts } from './config.ts';
|
|
3
|
+
export { loadHttpConfig, policy } from './config.ts';
|
|
4
|
+
export { makeBufferedConnector } from './connector.ts';
|
|
5
|
+
export { startServer, stopServer } from './server.ts';
|
|
6
|
+
export declare const serverHooks: PluginHooks;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { getPluginSettings } from '@coffer-org/server/plugin-runtime';
|
|
2
|
+
import { startServer, stopServer } from "./server.js";
|
|
3
|
+
export { loadHttpConfig, policy } from "./config.js";
|
|
4
|
+
export { makeBufferedConnector } from "./connector.js";
|
|
5
|
+
export { startServer, stopServer } from "./server.js";
|
|
6
|
+
export const serverHooks = {
|
|
7
|
+
init: async () => {
|
|
8
|
+
const { loadHttpConfig } = await import("./config.js");
|
|
9
|
+
const dbSettings = await getPluginSettings('http');
|
|
10
|
+
const cfg = loadHttpConfig({ dbSettings });
|
|
11
|
+
void startServer(cfg).catch((e) => console.warn(`[http] failed to start: ${e.message}`));
|
|
12
|
+
},
|
|
13
|
+
teardown: async () => {
|
|
14
|
+
await stopServer();
|
|
15
|
+
},
|
|
16
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { handleIncoming } from '@coffer-org/plugin-orchestrator/runtime';
|
|
2
|
+
import type { HttpConfig } from './config.ts';
|
|
3
|
+
export interface ServerDeps {
|
|
4
|
+
handleIncoming?: typeof handleIncoming;
|
|
5
|
+
}
|
|
6
|
+
export declare function startServer(cfg: HttpConfig, deps?: ServerDeps): Promise<void>;
|
|
7
|
+
export declare function stopServer(): Promise<void>;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { createServer } from 'node:http';
|
|
2
|
+
import { handleIncoming } from '@coffer-org/plugin-orchestrator/runtime';
|
|
3
|
+
import { policy } from "./config.js";
|
|
4
|
+
import { makeBufferedConnector } from "./connector.js";
|
|
5
|
+
const BIND_HOST = '127.0.0.1';
|
|
6
|
+
let server;
|
|
7
|
+
function readBody(req) {
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
9
|
+
const chunks = [];
|
|
10
|
+
req.on('data', (chunk) => chunks.push(chunk));
|
|
11
|
+
req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
|
|
12
|
+
req.on('error', reject);
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
function sendJson(res, status, body) {
|
|
16
|
+
const payload = JSON.stringify(body);
|
|
17
|
+
res.writeHead(status, {
|
|
18
|
+
'Content-Type': 'application/json',
|
|
19
|
+
'Content-Length': Buffer.byteLength(payload),
|
|
20
|
+
});
|
|
21
|
+
res.end(payload);
|
|
22
|
+
}
|
|
23
|
+
async function handleRequest(req, res, cfg, deps) {
|
|
24
|
+
const doHandle = deps.handleIncoming ?? handleIncoming;
|
|
25
|
+
if (req.method !== 'POST' || req.url !== '/message') {
|
|
26
|
+
sendJson(res, 404, { error: 'Not found' });
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
let body;
|
|
30
|
+
try {
|
|
31
|
+
const raw = await readBody(req);
|
|
32
|
+
body = JSON.parse(raw);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
sendJson(res, 400, { error: 'Invalid JSON body' });
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (typeof body !== 'object' || body === null) {
|
|
39
|
+
sendJson(res, 400, { error: 'Body must be a JSON object' });
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const { chatId, userId, text } = body;
|
|
43
|
+
if (typeof text !== 'string' || !text.trim()) {
|
|
44
|
+
sendJson(res, 400, { error: 'Missing required field: text' });
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const { connector, drain } = makeBufferedConnector();
|
|
48
|
+
await doHandle(connector, {
|
|
49
|
+
chatId: typeof chatId === 'string' ? chatId : 'http',
|
|
50
|
+
userId: typeof userId === 'string' ? userId : 'http',
|
|
51
|
+
text,
|
|
52
|
+
replyToId: null,
|
|
53
|
+
}, { policy: policy(cfg) });
|
|
54
|
+
sendJson(res, 200, { reply: drain().join('\n\n') });
|
|
55
|
+
}
|
|
56
|
+
export async function startServer(cfg, deps = {}) {
|
|
57
|
+
if (server)
|
|
58
|
+
return;
|
|
59
|
+
server = createServer((req, res) => {
|
|
60
|
+
handleRequest(req, res, cfg, deps).catch((err) => {
|
|
61
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
62
|
+
console.error(`[http-connector] request handling error: ${msg}`);
|
|
63
|
+
if (!res.headersSent) {
|
|
64
|
+
sendJson(res, 500, { error: 'Internal server error' });
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
await new Promise((resolve, reject) => {
|
|
69
|
+
server.listen(cfg.port, BIND_HOST, () => resolve());
|
|
70
|
+
server.once('error', reject);
|
|
71
|
+
});
|
|
72
|
+
console.log(`[http-connector] listening on http://${BIND_HOST}:${cfg.port}/message`);
|
|
73
|
+
}
|
|
74
|
+
export async function stopServer() {
|
|
75
|
+
if (!server)
|
|
76
|
+
return;
|
|
77
|
+
const s = server;
|
|
78
|
+
server = undefined;
|
|
79
|
+
await new Promise((resolve, reject) => {
|
|
80
|
+
s.close((err) => (err ? reject(err) : resolve()));
|
|
81
|
+
});
|
|
82
|
+
console.log('[http-connector] stopped');
|
|
83
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@coffer-org/plugin-http",
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"engines": {
|
|
6
|
+
"node": ">=24"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./runtime": {
|
|
17
|
+
"types": "./dist/runtime/index.d.ts",
|
|
18
|
+
"default": "./dist/runtime/index.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsc -b tsconfig.build.json",
|
|
23
|
+
"prepack": "npm run build && node ../../scripts/swap-exports.mjs dist",
|
|
24
|
+
"postpack": "node ../../scripts/swap-exports.mjs src",
|
|
25
|
+
"test": "node --import tsx --test \"src/runtime/*.test.ts\""
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@coffer-org/plugin-orchestrator": "^1.2.0",
|
|
29
|
+
"@coffer-org/sdk": "^1.2.0",
|
|
30
|
+
"@coffer-org/server": "^1.2.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {}
|
|
33
|
+
}
|