mcp-tenant-lib 0.1.1 → 0.1.2
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/tenant.d.ts +20 -0
- package/dist/tenant.js +43 -1
- package/dist/types.d.ts +5 -0
- package/dist/ws.js +2 -1
- package/package.json +1 -1
package/dist/tenant.d.ts
CHANGED
|
@@ -36,6 +36,26 @@ export declare class Tenant<TSchema, TValues> {
|
|
|
36
36
|
schema: TSchema;
|
|
37
37
|
store: Store<TValues>;
|
|
38
38
|
submitBus: EventEmitter;
|
|
39
|
+
/**
|
|
40
|
+
* Whether some caller currently has a `submitBus.once('submit', ...)`
|
|
41
|
+
* listener registered — i.e. wait_for_submit / define_form({wait:true})
|
|
42
|
+
* is actively blocked on this tenant right now. Tracked via submitBus's
|
|
43
|
+
* own newListener/removeListener events (see constructor) rather than a
|
|
44
|
+
* manual flag, so it can never drift from the real listener count.
|
|
45
|
+
* Broadcast to the browser as a 'waiting' WS message so the UI can show
|
|
46
|
+
* whether anyone is listening, without implying Submit is meaningless
|
|
47
|
+
* when nobody currently is (see `submitted`).
|
|
48
|
+
*/
|
|
49
|
+
waiting: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Whether the user has clicked Submit at least once since the form was
|
|
52
|
+
* last (re)defined. Set unconditionally on the 'submit' WS message,
|
|
53
|
+
* independent of `waiting` — the user can fill in and submit a form
|
|
54
|
+
* with no agent currently waiting (e.g. it was defined with wait:false,
|
|
55
|
+
* or the agent's turn ended), and a later wait_for_submit call or
|
|
56
|
+
* list_fields read should be able to see that they're done.
|
|
57
|
+
*/
|
|
58
|
+
submitted: boolean;
|
|
39
59
|
wsClients: Set<WebSocket>;
|
|
40
60
|
connections: Map<string, TenantConnection>;
|
|
41
61
|
lastActivityAt: number;
|
package/dist/tenant.js
CHANGED
|
@@ -39,6 +39,26 @@ export class Tenant {
|
|
|
39
39
|
schema;
|
|
40
40
|
store;
|
|
41
41
|
submitBus;
|
|
42
|
+
/**
|
|
43
|
+
* Whether some caller currently has a `submitBus.once('submit', ...)`
|
|
44
|
+
* listener registered — i.e. wait_for_submit / define_form({wait:true})
|
|
45
|
+
* is actively blocked on this tenant right now. Tracked via submitBus's
|
|
46
|
+
* own newListener/removeListener events (see constructor) rather than a
|
|
47
|
+
* manual flag, so it can never drift from the real listener count.
|
|
48
|
+
* Broadcast to the browser as a 'waiting' WS message so the UI can show
|
|
49
|
+
* whether anyone is listening, without implying Submit is meaningless
|
|
50
|
+
* when nobody currently is (see `submitted`).
|
|
51
|
+
*/
|
|
52
|
+
waiting = false;
|
|
53
|
+
/**
|
|
54
|
+
* Whether the user has clicked Submit at least once since the form was
|
|
55
|
+
* last (re)defined. Set unconditionally on the 'submit' WS message,
|
|
56
|
+
* independent of `waiting` — the user can fill in and submit a form
|
|
57
|
+
* with no agent currently waiting (e.g. it was defined with wait:false,
|
|
58
|
+
* or the agent's turn ended), and a later wait_for_submit call or
|
|
59
|
+
* list_fields read should be able to see that they're done.
|
|
60
|
+
*/
|
|
61
|
+
submitted = false;
|
|
42
62
|
wsClients;
|
|
43
63
|
connections = new Map();
|
|
44
64
|
#legacyManifest;
|
|
@@ -85,6 +105,16 @@ export class Tenant {
|
|
|
85
105
|
this.store = new Store(initialValues);
|
|
86
106
|
this.submitBus = new EventEmitter();
|
|
87
107
|
this.submitBus.setMaxListeners(0);
|
|
108
|
+
this.submitBus.on('newListener', (event) => {
|
|
109
|
+
if (event !== 'submit')
|
|
110
|
+
return;
|
|
111
|
+
queueMicrotask(() => this.#syncWaiting());
|
|
112
|
+
});
|
|
113
|
+
this.submitBus.on('removeListener', (event) => {
|
|
114
|
+
if (event !== 'submit')
|
|
115
|
+
return;
|
|
116
|
+
this.#syncWaiting();
|
|
117
|
+
});
|
|
88
118
|
this.wsClients = new Set();
|
|
89
119
|
this.lastActivityAt = Date.now();
|
|
90
120
|
this.store.onChange((field, value) => this.broadcastUpdate(field, value));
|
|
@@ -252,11 +282,12 @@ export class Tenant {
|
|
|
252
282
|
this.store.dispose();
|
|
253
283
|
this.schema = schema;
|
|
254
284
|
this.store = new Store(values);
|
|
285
|
+
this.submitted = false;
|
|
255
286
|
this.store.onChange((field, value) => this.broadcastUpdate(field, value));
|
|
256
287
|
this.broadcastReinit();
|
|
257
288
|
}
|
|
258
289
|
broadcastReinit() {
|
|
259
|
-
const payload = JSON.stringify({ type: 'reinit', schema: this.schema, state: this.store.snapshot() });
|
|
290
|
+
const payload = JSON.stringify({ type: 'reinit', schema: this.schema, state: this.store.snapshot(), waiting: this.waiting, submitted: this.submitted });
|
|
260
291
|
for (const client of this.wsClients) {
|
|
261
292
|
if (client.readyState === client.OPEN)
|
|
262
293
|
client.send(payload);
|
|
@@ -269,6 +300,17 @@ export class Tenant {
|
|
|
269
300
|
client.send(payload);
|
|
270
301
|
}
|
|
271
302
|
}
|
|
303
|
+
#syncWaiting() {
|
|
304
|
+
const nowWaiting = this.submitBus.listenerCount('submit') > 0;
|
|
305
|
+
if (nowWaiting === this.waiting)
|
|
306
|
+
return;
|
|
307
|
+
this.waiting = nowWaiting;
|
|
308
|
+
const payload = JSON.stringify({ type: 'waiting', waiting: this.waiting });
|
|
309
|
+
for (const client of this.wsClients) {
|
|
310
|
+
if (client.readyState === client.OPEN)
|
|
311
|
+
client.send(payload);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
272
314
|
dispose() {
|
|
273
315
|
this.submitBus.emit('submit', { __interrupted: true, __disposed: true, ...this.store.snapshot() });
|
|
274
316
|
this.store.dispose();
|
package/dist/types.d.ts
CHANGED
|
@@ -7,10 +7,15 @@ export type ServerMessage<TSchema = unknown, TValues = unknown> = {
|
|
|
7
7
|
type: 'init' | 'reinit';
|
|
8
8
|
schema: TSchema;
|
|
9
9
|
state: TValues;
|
|
10
|
+
waiting: boolean;
|
|
11
|
+
submitted: boolean;
|
|
10
12
|
} | {
|
|
11
13
|
type: 'update';
|
|
12
14
|
field: string;
|
|
13
15
|
value: unknown;
|
|
16
|
+
} | {
|
|
17
|
+
type: 'waiting';
|
|
18
|
+
waiting: boolean;
|
|
14
19
|
} | CallMessage;
|
|
15
20
|
export interface SetMessage {
|
|
16
21
|
type: 'set';
|
package/dist/ws.js
CHANGED
|
@@ -51,7 +51,7 @@ export function attachWebSocketServer(httpServer, port, initialSchema, initialVa
|
|
|
51
51
|
if (state)
|
|
52
52
|
state.isAlive = true;
|
|
53
53
|
});
|
|
54
|
-
ws.send(JSON.stringify({ type: 'init', schema: t.schema, state: t.store.snapshot() }));
|
|
54
|
+
ws.send(JSON.stringify({ type: 'init', schema: t.schema, state: t.store.snapshot(), waiting: t.waiting, submitted: t.submitted }));
|
|
55
55
|
ws.on('message', (raw) => {
|
|
56
56
|
t.touch();
|
|
57
57
|
let msg;
|
|
@@ -65,6 +65,7 @@ export function attachWebSocketServer(httpServer, port, initialSchema, initialVa
|
|
|
65
65
|
t.store.set(msg.field, msg.value);
|
|
66
66
|
}
|
|
67
67
|
if (msg.type === 'submit') {
|
|
68
|
+
t.submitted = true;
|
|
68
69
|
t.submitBus.emit('submit', { __interrupted: false, ...t.store.snapshot() });
|
|
69
70
|
}
|
|
70
71
|
if (msg.type === 'interrupt') {
|