@rowger_go/chatu 0.1.3
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/.github/workflows/ci.yml +30 -0
- package/.github/workflows/publish.yml +55 -0
- package/INSTALL.md +285 -0
- package/INSTALL.zh.md +285 -0
- package/LICENSE +21 -0
- package/README.md +293 -0
- package/README.zh.md +293 -0
- package/dist/index.d.ts +96 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1381 -0
- package/dist/index.js.map +1 -0
- package/dist/index.test.d.ts +5 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/index.test.js +334 -0
- package/dist/index.test.js.map +1 -0
- package/dist/sdk/adapters/cache.d.ts +94 -0
- package/dist/sdk/adapters/cache.d.ts.map +1 -0
- package/dist/sdk/adapters/cache.js +158 -0
- package/dist/sdk/adapters/cache.js.map +1 -0
- package/dist/sdk/adapters/cache.test.d.ts +14 -0
- package/dist/sdk/adapters/cache.test.d.ts.map +1 -0
- package/dist/sdk/adapters/cache.test.js +178 -0
- package/dist/sdk/adapters/cache.test.js.map +1 -0
- package/dist/sdk/adapters/default.d.ts +24 -0
- package/dist/sdk/adapters/default.d.ts.map +1 -0
- package/dist/sdk/adapters/default.js +151 -0
- package/dist/sdk/adapters/default.js.map +1 -0
- package/dist/sdk/adapters/webhub.d.ts +336 -0
- package/dist/sdk/adapters/webhub.d.ts.map +1 -0
- package/dist/sdk/adapters/webhub.js +663 -0
- package/dist/sdk/adapters/webhub.js.map +1 -0
- package/dist/sdk/adapters/websocket.d.ts +133 -0
- package/dist/sdk/adapters/websocket.d.ts.map +1 -0
- package/dist/sdk/adapters/websocket.js +314 -0
- package/dist/sdk/adapters/websocket.js.map +1 -0
- package/dist/sdk/core/channel.d.ts +104 -0
- package/dist/sdk/core/channel.d.ts.map +1 -0
- package/dist/sdk/core/channel.js +158 -0
- package/dist/sdk/core/channel.js.map +1 -0
- package/dist/sdk/index.d.ts +27 -0
- package/dist/sdk/index.d.ts.map +1 -0
- package/dist/sdk/index.js +33 -0
- package/dist/sdk/index.js.map +1 -0
- package/dist/sdk/types/adapters.d.ts +128 -0
- package/dist/sdk/types/adapters.d.ts.map +1 -0
- package/dist/sdk/types/adapters.js +10 -0
- package/dist/sdk/types/adapters.js.map +1 -0
- package/dist/sdk/types/channel.d.ts +270 -0
- package/dist/sdk/types/channel.d.ts.map +1 -0
- package/dist/sdk/types/channel.js +36 -0
- package/dist/sdk/types/channel.js.map +1 -0
- package/docs/channel/01-overview.md +117 -0
- package/docs/channel/02-configuration.md +138 -0
- package/docs/channel/03-capabilities.md +86 -0
- package/docs/channel/04-api-reference.md +394 -0
- package/docs/channel/05-message-protocol.md +194 -0
- package/docs/channel/06-security.md +83 -0
- package/docs/channel/README.md +30 -0
- package/docs/sdk/README.md +13 -0
- package/docs/sdk/v2026.1.29-v2026.2.19.md +630 -0
- package/jest.config.js +19 -0
- package/openclaw.plugin.json +113 -0
- package/package.json +74 -0
- package/run-poll.mjs +209 -0
- package/scripts/reload-plugin.sh +78 -0
- package/src/index.test.ts +432 -0
- package/src/index.ts +1638 -0
- package/src/sdk/adapters/cache.test.ts +205 -0
- package/src/sdk/adapters/cache.ts +193 -0
- package/src/sdk/adapters/default.ts +196 -0
- package/src/sdk/adapters/webhub.ts +857 -0
- package/src/sdk/adapters/websocket.ts +378 -0
- package/src/sdk/core/channel.ts +230 -0
- package/src/sdk/index.ts +36 -0
- package/src/sdk/types/adapters.ts +169 -0
- package/src/sdk/types/channel.ts +346 -0
- package/tsconfig.json +31 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/******************************************************************
|
|
3
|
+
* Plugin Local Message Cache (cache.ts)
|
|
4
|
+
*
|
|
5
|
+
* In-memory FIFO queue for outbound messages that couldn't be sent
|
|
6
|
+
* while the WebSocket was disconnected.
|
|
7
|
+
*
|
|
8
|
+
* Key behaviour (spec FR-007/US2):
|
|
9
|
+
* - Capacity limited to CHATU_CACHE_MAX (default 1000)
|
|
10
|
+
* - On overflow: oldest item is evicted; PluginLogger.warn is called
|
|
11
|
+
* with a SINGLE STRING (constitution §VII — NON-NEGOTIABLE)
|
|
12
|
+
* - Optional JSON file persistence via CHATU_CACHE_FILE env var
|
|
13
|
+
* - flush(sendFn) sends items in FIFO order; ack(id) marks delivered
|
|
14
|
+
*
|
|
15
|
+
* @see specs/001-plugin-channel-realtime/tasks.md T013
|
|
16
|
+
******************************************************************/
|
|
17
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
18
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.MessageCache = void 0;
|
|
22
|
+
const fs_1 = __importDefault(require("fs"));
|
|
23
|
+
const path_1 = __importDefault(require("path"));
|
|
24
|
+
const DEFAULT_CAPACITY = 1000;
|
|
25
|
+
/**
|
|
26
|
+
* MessageCache — FIFO queue for offline-buffered outbound messages.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* const cache = new MessageCache({ logger: api.logger });
|
|
31
|
+
* cache.enqueue({ id: uuid(), channelId: 'wh_ch_xxx', content: { text: 'hello' }, enqueuedAt: Date.now(), status: 'pending' });
|
|
32
|
+
* await cache.flush(async (msg) => adapter.send(msg));
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
class MessageCache {
|
|
36
|
+
constructor(options = {}) {
|
|
37
|
+
this.queue = [];
|
|
38
|
+
this.maxCapacity =
|
|
39
|
+
options.maxCapacity ??
|
|
40
|
+
(process.env.CHATU_CACHE_MAX ? parseInt(process.env.CHATU_CACHE_MAX, 10) : DEFAULT_CAPACITY);
|
|
41
|
+
this.filePath =
|
|
42
|
+
options.filePath ??
|
|
43
|
+
(process.env.CHATU_CACHE_FILE ? path_1.default.resolve(process.env.CHATU_CACHE_FILE) : undefined);
|
|
44
|
+
this.logger = options.logger;
|
|
45
|
+
// Restore from file if configured
|
|
46
|
+
if (this.filePath) {
|
|
47
|
+
this.loadFromFile();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// ─── Public API ──────────────────────────────────────────────────────────────
|
|
51
|
+
/**
|
|
52
|
+
* Enqueue a message for later delivery.
|
|
53
|
+
* If at capacity, evicts the oldest pending item and logs a warning.
|
|
54
|
+
*/
|
|
55
|
+
enqueue(msg) {
|
|
56
|
+
if (this.queue.length >= this.maxCapacity) {
|
|
57
|
+
const dropped = this.queue.shift();
|
|
58
|
+
if (dropped && this.logger) {
|
|
59
|
+
// §VII: PluginLogger.warn must receive a SINGLE STRING — no object argument
|
|
60
|
+
this.logger.warn('cache_capacity_exceeded: channelId=' + msg.channelId + ' dropped=' + dropped.id);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
this.queue.push(msg);
|
|
64
|
+
this.persist();
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Flush all 'pending' items in FIFO order by calling sendFn for each.
|
|
68
|
+
* Items that sendFn resolves successfully are marked 'submitted'.
|
|
69
|
+
* Items where sendFn throws remain 'pending' for the next flush.
|
|
70
|
+
*
|
|
71
|
+
* Returns the number of successfully flushed items.
|
|
72
|
+
*/
|
|
73
|
+
async flush(sendFn) {
|
|
74
|
+
let flushed = 0;
|
|
75
|
+
const pending = this.queue.filter((m) => m.status === 'pending');
|
|
76
|
+
for (const msg of pending) {
|
|
77
|
+
try {
|
|
78
|
+
await sendFn(msg);
|
|
79
|
+
msg.status = 'submitted';
|
|
80
|
+
flushed++;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// Leave as pending — will retry on next flush
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
this.persist();
|
|
88
|
+
return flushed;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Acknowledge delivery of a message by its id.
|
|
92
|
+
* Removes it from the queue to prevent duplicate re-sends.
|
|
93
|
+
*/
|
|
94
|
+
ack(id) {
|
|
95
|
+
const idx = this.queue.findIndex((m) => m.id === id);
|
|
96
|
+
if (idx !== -1) {
|
|
97
|
+
this.queue.splice(idx, 1);
|
|
98
|
+
this.persist();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Returns a snapshot of the current queue (read-only copy).
|
|
103
|
+
*/
|
|
104
|
+
snapshot() {
|
|
105
|
+
return [...this.queue];
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Number of items currently in the queue.
|
|
109
|
+
*/
|
|
110
|
+
get size() {
|
|
111
|
+
return this.queue.length;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Number of pending (not yet ACKed) items.
|
|
115
|
+
*/
|
|
116
|
+
get pendingCount() {
|
|
117
|
+
return this.queue.filter((m) => m.status === 'pending').length;
|
|
118
|
+
}
|
|
119
|
+
// ─── Persistence ─────────────────────────────────────────────────────────────
|
|
120
|
+
/**
|
|
121
|
+
* Persist the current queue to the JSON file (if configured).
|
|
122
|
+
* Errors are silently swallowed to avoid disrupting the main flow.
|
|
123
|
+
*/
|
|
124
|
+
persist() {
|
|
125
|
+
if (!this.filePath)
|
|
126
|
+
return;
|
|
127
|
+
try {
|
|
128
|
+
const dir = path_1.default.dirname(this.filePath);
|
|
129
|
+
if (!fs_1.default.existsSync(dir))
|
|
130
|
+
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
131
|
+
fs_1.default.writeFileSync(this.filePath, JSON.stringify(this.queue, null, 2), 'utf-8');
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// best-effort: silently ignore fs errors
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Load queue from the JSON file on startup (if the file exists).
|
|
139
|
+
*/
|
|
140
|
+
loadFromFile() {
|
|
141
|
+
if (!this.filePath)
|
|
142
|
+
return;
|
|
143
|
+
try {
|
|
144
|
+
if (!fs_1.default.existsSync(this.filePath))
|
|
145
|
+
return;
|
|
146
|
+
const raw = fs_1.default.readFileSync(this.filePath, 'utf-8');
|
|
147
|
+
const parsed = JSON.parse(raw);
|
|
148
|
+
if (Array.isArray(parsed)) {
|
|
149
|
+
this.queue = parsed;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
// best-effort: ignore corrupt/missing files
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
exports.MessageCache = MessageCache;
|
|
158
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../../src/sdk/adapters/cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* T037b — MessageCache unit tests
|
|
3
|
+
*
|
|
4
|
+
* constitution §IV: New modules must have a test file.
|
|
5
|
+
*
|
|
6
|
+
* Tests cover:
|
|
7
|
+
* - enqueue → FIFO order guarantee
|
|
8
|
+
* - Capacity limit: evicts oldest + logger.warn (single STRING — §VII)
|
|
9
|
+
* - flush → calls sendFn in FIFO order; marks submitted
|
|
10
|
+
* - ack → removes item, prevents re-send
|
|
11
|
+
* - File persistence: write then re-instantiate → queue restored
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=cache.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.test.d.ts","sourceRoot":"","sources":["../../../src/sdk/adapters/cache.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* T037b — MessageCache unit tests
|
|
4
|
+
*
|
|
5
|
+
* constitution §IV: New modules must have a test file.
|
|
6
|
+
*
|
|
7
|
+
* Tests cover:
|
|
8
|
+
* - enqueue → FIFO order guarantee
|
|
9
|
+
* - Capacity limit: evicts oldest + logger.warn (single STRING — §VII)
|
|
10
|
+
* - flush → calls sendFn in FIFO order; marks submitted
|
|
11
|
+
* - ack → removes item, prevents re-send
|
|
12
|
+
* - File persistence: write then re-instantiate → queue restored
|
|
13
|
+
*/
|
|
14
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
15
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
16
|
+
};
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
const fs_1 = __importDefault(require("fs"));
|
|
19
|
+
const os_1 = __importDefault(require("os"));
|
|
20
|
+
const path_1 = __importDefault(require("path"));
|
|
21
|
+
const cache_1 = require("../../sdk/adapters/cache");
|
|
22
|
+
function makeMsg(id, channelId = 'ch-1') {
|
|
23
|
+
return { id, channelId, content: { text: `msg-${id}` }, enqueuedAt: Date.now(), status: 'pending' };
|
|
24
|
+
}
|
|
25
|
+
describe('MessageCache', () => {
|
|
26
|
+
// ── enqueue / FIFO ──────────────────────────────────────────────────────────
|
|
27
|
+
describe('enqueue', () => {
|
|
28
|
+
it('maintains FIFO insertion order in snapshot', () => {
|
|
29
|
+
const cache = new cache_1.MessageCache();
|
|
30
|
+
cache.enqueue(makeMsg('a'));
|
|
31
|
+
cache.enqueue(makeMsg('b'));
|
|
32
|
+
cache.enqueue(makeMsg('c'));
|
|
33
|
+
const ids = cache.snapshot().map((m) => m.id);
|
|
34
|
+
expect(ids).toEqual(['a', 'b', 'c']);
|
|
35
|
+
});
|
|
36
|
+
it('size reflects enqueued count', () => {
|
|
37
|
+
const cache = new cache_1.MessageCache();
|
|
38
|
+
cache.enqueue(makeMsg('x'));
|
|
39
|
+
cache.enqueue(makeMsg('y'));
|
|
40
|
+
expect(cache.size).toBe(2);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
// ── Capacity limit ──────────────────────────────────────────────────────────
|
|
44
|
+
describe('capacity enforcement', () => {
|
|
45
|
+
it('evicts the oldest item when limit is reached', () => {
|
|
46
|
+
const cache = new cache_1.MessageCache({ maxCapacity: 3 });
|
|
47
|
+
cache.enqueue(makeMsg('first'));
|
|
48
|
+
cache.enqueue(makeMsg('second'));
|
|
49
|
+
cache.enqueue(makeMsg('third'));
|
|
50
|
+
cache.enqueue(makeMsg('fourth')); // should evict 'first'
|
|
51
|
+
const ids = cache.snapshot().map((m) => m.id);
|
|
52
|
+
expect(ids).not.toContain('first');
|
|
53
|
+
expect(ids).toContain('fourth');
|
|
54
|
+
expect(cache.size).toBe(3);
|
|
55
|
+
});
|
|
56
|
+
it('calls logger.warn with a SINGLE STRING on eviction (§VII)', () => {
|
|
57
|
+
const warnMessages = [];
|
|
58
|
+
const logger = { warn: (msg) => { warnMessages.push(msg); } };
|
|
59
|
+
const cache = new cache_1.MessageCache({ maxCapacity: 1, logger });
|
|
60
|
+
cache.enqueue(makeMsg('m1', 'ch-test'));
|
|
61
|
+
cache.enqueue(makeMsg('m2', 'ch-test')); // evicts 'm1'
|
|
62
|
+
expect(warnMessages.length).toBe(1);
|
|
63
|
+
// Must be a string — not an object (§VII)
|
|
64
|
+
expect(typeof warnMessages[0]).toBe('string');
|
|
65
|
+
expect(warnMessages[0]).toContain('cache_capacity_exceeded');
|
|
66
|
+
expect(warnMessages[0]).toContain('ch-test');
|
|
67
|
+
expect(warnMessages[0]).toContain('m1');
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
// ── flush ───────────────────────────────────────────────────────────────────
|
|
71
|
+
describe('flush', () => {
|
|
72
|
+
it('calls sendFn for each pending message in FIFO order', async () => {
|
|
73
|
+
const cache = new cache_1.MessageCache();
|
|
74
|
+
cache.enqueue(makeMsg('p1'));
|
|
75
|
+
cache.enqueue(makeMsg('p2'));
|
|
76
|
+
cache.enqueue(makeMsg('p3'));
|
|
77
|
+
const order = [];
|
|
78
|
+
const count = await cache.flush(async (msg) => {
|
|
79
|
+
order.push(msg.id);
|
|
80
|
+
});
|
|
81
|
+
expect(count).toBe(3);
|
|
82
|
+
expect(order).toEqual(['p1', 'p2', 'p3']);
|
|
83
|
+
});
|
|
84
|
+
it('marks flushed messages as submitted', async () => {
|
|
85
|
+
const cache = new cache_1.MessageCache();
|
|
86
|
+
cache.enqueue(makeMsg('s1'));
|
|
87
|
+
await cache.flush(async () => { });
|
|
88
|
+
const snap = cache.snapshot();
|
|
89
|
+
expect(snap[0].status).toBe('submitted');
|
|
90
|
+
});
|
|
91
|
+
it('stops flushing on first sendFn error, leaving remaining as pending', async () => {
|
|
92
|
+
const cache = new cache_1.MessageCache();
|
|
93
|
+
cache.enqueue(makeMsg('ok1'));
|
|
94
|
+
cache.enqueue(makeMsg('fail'));
|
|
95
|
+
cache.enqueue(makeMsg('ok2'));
|
|
96
|
+
let calls = 0;
|
|
97
|
+
await cache.flush(async (msg) => {
|
|
98
|
+
calls++;
|
|
99
|
+
if (msg.id === 'fail')
|
|
100
|
+
throw new Error('send failed');
|
|
101
|
+
});
|
|
102
|
+
// Stopped at 'fail' — only 'ok1' submitted
|
|
103
|
+
expect(calls).toBe(2);
|
|
104
|
+
const snaps = cache.snapshot();
|
|
105
|
+
expect(snaps.find((m) => m.id === 'ok1')?.status).toBe('submitted');
|
|
106
|
+
expect(snaps.find((m) => m.id === 'fail')?.status).toBe('pending');
|
|
107
|
+
expect(snaps.find((m) => m.id === 'ok2')?.status).toBe('pending');
|
|
108
|
+
});
|
|
109
|
+
it('does not re-send already-submitted messages on subsequent flush', async () => {
|
|
110
|
+
const cache = new cache_1.MessageCache();
|
|
111
|
+
cache.enqueue(makeMsg('d1'));
|
|
112
|
+
await cache.flush(async () => { });
|
|
113
|
+
const sentIds = [];
|
|
114
|
+
await cache.flush(async (msg) => { sentIds.push(msg.id); });
|
|
115
|
+
expect(sentIds).not.toContain('d1');
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
// ── ack ─────────────────────────────────────────────────────────────────────
|
|
119
|
+
describe('ack', () => {
|
|
120
|
+
it('removes the message from the queue by id', () => {
|
|
121
|
+
const cache = new cache_1.MessageCache();
|
|
122
|
+
cache.enqueue(makeMsg('ack-1'));
|
|
123
|
+
cache.enqueue(makeMsg('ack-2'));
|
|
124
|
+
cache.ack('ack-1');
|
|
125
|
+
const ids = cache.snapshot().map((m) => m.id);
|
|
126
|
+
expect(ids).not.toContain('ack-1');
|
|
127
|
+
expect(ids).toContain('ack-2');
|
|
128
|
+
});
|
|
129
|
+
it('prevents the acked message from being re-sent on flush', async () => {
|
|
130
|
+
const cache = new cache_1.MessageCache();
|
|
131
|
+
cache.enqueue(makeMsg('r1'));
|
|
132
|
+
cache.enqueue(makeMsg('r2'));
|
|
133
|
+
cache.ack('r1');
|
|
134
|
+
const sent = [];
|
|
135
|
+
await cache.flush(async (msg) => { sent.push(msg.id); });
|
|
136
|
+
expect(sent).not.toContain('r1');
|
|
137
|
+
expect(sent).toContain('r2');
|
|
138
|
+
});
|
|
139
|
+
it('is a no-op for unknown ids', () => {
|
|
140
|
+
const cache = new cache_1.MessageCache();
|
|
141
|
+
cache.enqueue(makeMsg('x'));
|
|
142
|
+
expect(() => cache.ack('nonexistent')).not.toThrow();
|
|
143
|
+
expect(cache.size).toBe(1);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
// ── File persistence ─────────────────────────────────────────────────────────
|
|
147
|
+
describe('file persistence', () => {
|
|
148
|
+
let tmpFile;
|
|
149
|
+
beforeEach(() => {
|
|
150
|
+
tmpFile = path_1.default.join(os_1.default.tmpdir(), `cache-test-${Date.now()}.json`);
|
|
151
|
+
});
|
|
152
|
+
afterEach(() => {
|
|
153
|
+
try {
|
|
154
|
+
fs_1.default.unlinkSync(tmpFile);
|
|
155
|
+
}
|
|
156
|
+
catch { /* ignore */ }
|
|
157
|
+
});
|
|
158
|
+
it('persists queue to file and restores on re-instantiation', () => {
|
|
159
|
+
const cache1 = new cache_1.MessageCache({ filePath: tmpFile });
|
|
160
|
+
cache1.enqueue(makeMsg('persist-1'));
|
|
161
|
+
cache1.enqueue(makeMsg('persist-2'));
|
|
162
|
+
// Re-instantiate from same file path
|
|
163
|
+
const cache2 = new cache_1.MessageCache({ filePath: tmpFile });
|
|
164
|
+
const ids = cache2.snapshot().map((m) => m.id);
|
|
165
|
+
expect(ids).toEqual(['persist-1', 'persist-2']);
|
|
166
|
+
});
|
|
167
|
+
it('starts with empty queue if file does not exist', () => {
|
|
168
|
+
const cache = new cache_1.MessageCache({ filePath: '/tmp/definitely-does-not-exist-xyz123.json' });
|
|
169
|
+
expect(cache.size).toBe(0);
|
|
170
|
+
});
|
|
171
|
+
it('starts with empty queue if file is corrupt JSON', () => {
|
|
172
|
+
fs_1.default.writeFileSync(tmpFile, 'not valid json');
|
|
173
|
+
const cache = new cache_1.MessageCache({ filePath: tmpFile });
|
|
174
|
+
expect(cache.size).toBe(0);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
//# sourceMappingURL=cache.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.test.js","sourceRoot":"","sources":["../../../src/sdk/adapters/cache.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/******************************************************************
|
|
2
|
+
* Channel SDK - Default Adapter Factory
|
|
3
|
+
*
|
|
4
|
+
* OpenClaw Channel SDK 的默认适配器工厂
|
|
5
|
+
*
|
|
6
|
+
* @see https://github.com/chatu-ai/openclaw-web-hub-channel
|
|
7
|
+
******************************************************************/
|
|
8
|
+
import { ConnectionConfig } from '../types/channel';
|
|
9
|
+
import type { ConnectionAdapter, MessageAdapter, HeartbeatAdapter, AuthAdapter, CapabilitiesAdapter, LoggerAdapter, AdapterFactory } from '../types/adapters';
|
|
10
|
+
/**
|
|
11
|
+
* 默认适配器工厂 [Channel SDK 标准]
|
|
12
|
+
*
|
|
13
|
+
* 提供所有适配器的默认实现
|
|
14
|
+
*/
|
|
15
|
+
export declare class DefaultAdapterFactory implements AdapterFactory {
|
|
16
|
+
createConnectionAdapter(config: ConnectionConfig): ConnectionAdapter;
|
|
17
|
+
createMessageAdapter(): MessageAdapter;
|
|
18
|
+
createHeartbeatAdapter(): HeartbeatAdapter;
|
|
19
|
+
createAuthAdapter(token?: string): AuthAdapter;
|
|
20
|
+
createCapabilitiesAdapter(): CapabilitiesAdapter;
|
|
21
|
+
createLoggerAdapter(): LoggerAdapter;
|
|
22
|
+
}
|
|
23
|
+
export declare function createDefaultFactory(): DefaultAdapterFactory;
|
|
24
|
+
//# sourceMappingURL=default.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"default.d.ts","sourceRoot":"","sources":["../../../src/sdk/adapters/default.ts"],"names":[],"mappings":"AAAA;;;;;;oEAMoE;AAEpE,OAAO,EACL,gBAAgB,EAMjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EACV,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,mBAAmB,EACnB,aAAa,EAGb,cAAc,EACf,MAAM,mBAAmB,CAAC;AAgI3B;;;;GAIG;AACH,qBAAa,qBAAsB,YAAW,cAAc;IAC1D,uBAAuB,CAAC,MAAM,EAAE,gBAAgB,GAAG,iBAAiB;IAIpE,oBAAoB,IAAI,cAAc;IAItC,sBAAsB,IAAI,gBAAgB;IAI1C,iBAAiB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,WAAW;IAI9C,yBAAyB,IAAI,mBAAmB;IAIhD,mBAAmB,IAAI,aAAa;CAGrC;AAOD,wBAAgB,oBAAoB,IAAI,qBAAqB,CAK5D"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/******************************************************************
|
|
3
|
+
* Channel SDK - Default Adapter Factory
|
|
4
|
+
*
|
|
5
|
+
* OpenClaw Channel SDK 的默认适配器工厂
|
|
6
|
+
*
|
|
7
|
+
* @see https://github.com/chatu-ai/openclaw-web-hub-channel
|
|
8
|
+
******************************************************************/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.DefaultAdapterFactory = void 0;
|
|
11
|
+
exports.createDefaultFactory = createDefaultFactory;
|
|
12
|
+
const channel_1 = require("../types/channel");
|
|
13
|
+
const websocket_1 = require("./websocket");
|
|
14
|
+
/**
|
|
15
|
+
* 消息适配器实现 [Channel SDK 标准]
|
|
16
|
+
*/
|
|
17
|
+
class DefaultMessageAdapter {
|
|
18
|
+
parseInbound(raw) {
|
|
19
|
+
return raw;
|
|
20
|
+
}
|
|
21
|
+
formatOutbound(message) {
|
|
22
|
+
return message;
|
|
23
|
+
}
|
|
24
|
+
validate(message) {
|
|
25
|
+
return message && typeof message === 'object';
|
|
26
|
+
}
|
|
27
|
+
sanitize(text) {
|
|
28
|
+
return text
|
|
29
|
+
.replace(/</g, '<')
|
|
30
|
+
.replace(/>/g, '>')
|
|
31
|
+
.replace(/"/g, '"');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 心跳适配器实现 [Channel SDK 标准]
|
|
36
|
+
*/
|
|
37
|
+
class DefaultHeartbeatAdapter {
|
|
38
|
+
constructor(timeout = 10000) {
|
|
39
|
+
this.lastResponse = Date.now();
|
|
40
|
+
this.timeout = timeout;
|
|
41
|
+
}
|
|
42
|
+
async send() {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
handleResponse() {
|
|
46
|
+
this.lastResponse = Date.now();
|
|
47
|
+
}
|
|
48
|
+
isTimeout() {
|
|
49
|
+
return Date.now() - this.lastResponse > this.timeout;
|
|
50
|
+
}
|
|
51
|
+
getNextHeartbeatTime() {
|
|
52
|
+
return Date.now() + 30000;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 认证适配器实现 [Channel SDK 标准]
|
|
57
|
+
*/
|
|
58
|
+
class DefaultAuthAdapter {
|
|
59
|
+
constructor(token) {
|
|
60
|
+
this.token = token;
|
|
61
|
+
}
|
|
62
|
+
getAuthHeaders() {
|
|
63
|
+
return {
|
|
64
|
+
'Authorization': `Bearer ${this.token}`,
|
|
65
|
+
'Content-Type': 'application/json',
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
validateResponse(response) {
|
|
69
|
+
return response !== null && response !== undefined;
|
|
70
|
+
}
|
|
71
|
+
async refreshToken() {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 能力适配器实现 [Channel SDK 标准]
|
|
77
|
+
*/
|
|
78
|
+
class DefaultCapabilitiesAdapter {
|
|
79
|
+
async getCapabilities() {
|
|
80
|
+
return {
|
|
81
|
+
messageTypes: [
|
|
82
|
+
channel_1.MessageType.TEXT,
|
|
83
|
+
channel_1.MessageType.IMAGE,
|
|
84
|
+
channel_1.MessageType.VIDEO,
|
|
85
|
+
channel_1.MessageType.AUDIO,
|
|
86
|
+
channel_1.MessageType.FILE,
|
|
87
|
+
],
|
|
88
|
+
targetTypes: [channel_1.TargetType.USER, channel_1.TargetType.GROUP],
|
|
89
|
+
richFormats: ['markdown'],
|
|
90
|
+
attachments: true,
|
|
91
|
+
reply: true,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
hasCapability(capability) {
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* 日志适配器实现 [Channel SDK 标准]
|
|
100
|
+
*/
|
|
101
|
+
class DefaultLoggerAdapter {
|
|
102
|
+
debug(message, data) {
|
|
103
|
+
console.debug(`[DEBUG] ${message}`, data || '');
|
|
104
|
+
}
|
|
105
|
+
info(message, data) {
|
|
106
|
+
console.info(`[INFO] ${message}`, data || '');
|
|
107
|
+
}
|
|
108
|
+
warn(message, data) {
|
|
109
|
+
console.warn(`[WARN] ${message}`, data || '');
|
|
110
|
+
}
|
|
111
|
+
error(message, error) {
|
|
112
|
+
console.error(`[ERROR] ${message}`, error || '');
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* 默认适配器工厂 [Channel SDK 标准]
|
|
117
|
+
*
|
|
118
|
+
* 提供所有适配器的默认实现
|
|
119
|
+
*/
|
|
120
|
+
class DefaultAdapterFactory {
|
|
121
|
+
createConnectionAdapter(config) {
|
|
122
|
+
return new websocket_1.WebSocketAdapter(config);
|
|
123
|
+
}
|
|
124
|
+
createMessageAdapter() {
|
|
125
|
+
return new DefaultMessageAdapter();
|
|
126
|
+
}
|
|
127
|
+
createHeartbeatAdapter() {
|
|
128
|
+
return new DefaultHeartbeatAdapter();
|
|
129
|
+
}
|
|
130
|
+
createAuthAdapter(token) {
|
|
131
|
+
return new DefaultAuthAdapter(token || '');
|
|
132
|
+
}
|
|
133
|
+
createCapabilitiesAdapter() {
|
|
134
|
+
return new DefaultCapabilitiesAdapter();
|
|
135
|
+
}
|
|
136
|
+
createLoggerAdapter() {
|
|
137
|
+
return new DefaultLoggerAdapter();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
exports.DefaultAdapterFactory = DefaultAdapterFactory;
|
|
141
|
+
/**
|
|
142
|
+
* 创建默认工厂单例 [Channel SDK 标准]
|
|
143
|
+
*/
|
|
144
|
+
let factory = null;
|
|
145
|
+
function createDefaultFactory() {
|
|
146
|
+
if (!factory) {
|
|
147
|
+
factory = new DefaultAdapterFactory();
|
|
148
|
+
}
|
|
149
|
+
return factory;
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=default.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"default.js","sourceRoot":"","sources":["../../../src/sdk/adapters/default.ts"],"names":[],"mappings":"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"}
|