Row 94, round 2. Rocko built it, Dewey approved it (comment 28104) on manifest 53b01ea9 (16 paths, basee918a915). The bus keeps a messages view with read state, where delivered but not read stays read:false. The CLI gains messages and follow, and inbox leaves out messages already read while inbox --json stays byte-compatible. The Console gets a Messages page and an unread count in the nav. Mos gave the go under decision 123 (public/ files). Sage gate on645489e4plus the patch, 12:52:14Z to 12:55:44Z: bus 115, cli 129, webui 104, all fail 0. Every scripts/test-*.sh exited 0 (auth 15, conductor 17, config 24, discord 66, extension-package 18, foundation 44, queue 27, release 14, task 98). Manifest 16/16 before and after. Co-Authored-By: Claude Opus 5.5 <[email protected]>
60 lines
3.6 KiB
JavaScript
60 lines
3.6 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { Broker } from '../src/broker.mjs';
|
|
import { BUSINESSES, broker } from '../../cli/tests/helpers.mjs';
|
|
import { views } from '../src/views.mjs';
|
|
const call = (s, cap, verb, args = {}) => s.b.request(cap, { verb, args });
|
|
const send = (s, body, to = 'human') => call(s, s.coder, 'message.send', { to, body, class: 'INFO' }).id;
|
|
test('messages pages all human messages newest first without writes; read state is history', t => {
|
|
const s = broker(t), ids = [];
|
|
for (let i = 0; i < 205; i++) ids.push(send(s, `note ${i}`));
|
|
send(s, 'role only', 'pm');
|
|
const before = s.store.all('SELECT * FROM deliveries');
|
|
const first = s.read('messages');
|
|
assert.equal(first.messages.length, 50);
|
|
assert.equal(first.total, 205); assert.equal(first.unread, 205);
|
|
assert.deepEqual(first.messages.map(m => m.id), ids.slice(-50).reverse());
|
|
assert.ok(first.messages.every(m => m.read === false && m.in_reply_to === null));
|
|
assert.equal(first.next, ids[155]);
|
|
const second = s.read('messages', { limit: 200, after: first.next });
|
|
assert.deepEqual(second.messages.map(m => m.id), ids.slice(0,155).reverse());
|
|
assert.equal(second.next, null);
|
|
assert.equal(s.read('messages', {limit:200}).messages.length,200);
|
|
assert.deepEqual(s.store.all('SELECT * FROM deliveries'), before);
|
|
assert.deepEqual(call(s,s.human,'messages'), first);
|
|
const got = call(s,s.human,'message.receive');
|
|
call(s,s.human,'message.read',{id:got[0].id});
|
|
const read = s.read('messages', {limit:200, after:ids[1]});
|
|
assert.equal(read.messages[0].read,true); assert.equal(read.unread,204);
|
|
const delivered = s.read('messages', {limit:200, after:ids[2]}).messages.find(m => m.id === got[1].id);
|
|
assert.equal(delivered.read,false,'delivered without a read receipt remains unread');
|
|
});
|
|
test('messages refuses role callers, invalid paging and cursors outside this human feed', t => {
|
|
const s=broker(t); send(s,'hello'); const other=send(s,'role','pm');
|
|
for (const args of [{limit:0},{limit:201},{limit:1.5},{limit:'2'},{after:''},{after:3},{extra:true}])
|
|
assert.throws(()=>s.read('messages',args),{code:'invalid-request'});
|
|
for (const after of ['missing',other]) assert.throws(()=>s.read('messages',{after}),{code:'message-not-found'});
|
|
assert.throws(()=>call(s,s.coder,'messages'),{code:'human-required'});
|
|
const cap=s.b.bindReader({business:'demo'});
|
|
assert.throws(()=>call(s,cap,'message.receive'),{code:'read-only'});
|
|
});
|
|
test('views messages passes only its paging arguments through', async()=>{
|
|
const calls=[]; const v=views({call:async(...args)=>(calls.push(args),{messages:[],next:null})});
|
|
await v.messages({limit:2,after:'m-1'}); await v.messages();
|
|
assert.deepEqual(calls,[['messages',{limit:2,after:'m-1'}],['messages',{}]]);
|
|
});
|
|
|
|
test('messages isolates businesses even with a valid foreign cursor', t => {
|
|
const s=broker(t);
|
|
// A second broker shares this test's store but binds a separate business.
|
|
const otherBroker=new Broker({store:s.store,businesses:{other:{...BUSINESSES.demo,id:'other'}}});
|
|
const agent=otherBroker.bindLaunch({business:'other',role:'coder',run:'other-run',harness:'pi'});
|
|
otherBroker.request(agent,{verb:'role.claim'});
|
|
const foreign=otherBroker.request(agent,{verb:'message.send',args:{to:'human',body:'foreign'}}).id;
|
|
const own=send(s,'own');
|
|
assert.deepEqual(s.read('messages').messages.map(m=>m.id),[own]);
|
|
assert.throws(()=>s.read('messages',{after:foreign}),{code:'message-not-found'});
|
|
const reader=otherBroker.bindReader({business:'other'});
|
|
assert.deepEqual(otherBroker.request(reader,{verb:'messages'}).messages.map(m=>m.id),[foreign]);
|
|
});
|