@band-ai/band-sdk-core 0.4.1 → 0.5.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/README.md +40 -1
- package/band_sdk_core.js +261 -0
- package/band_sdk_core_bg.wasm +0 -0
- package/index.d.ts +50 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -54,7 +54,7 @@ exception class.
|
|
|
54
54
|
|
|
55
55
|
### Delivery-state runtime classes
|
|
56
56
|
|
|
57
|
-
`ClaimRegistry`, `RetryTracker`, and `
|
|
57
|
+
`ClaimRegistry`, `RetryTracker`, `ParticipantRoster`, and `SubscriptionTracker` are the
|
|
58
58
|
inbound-delivery runtime state classes — lifecycle and design decisions:
|
|
59
59
|
[`runtime-state-policy.md`](https://github.com/band-ai/band-sdk-core/blob/main/crates/core/docs/runtime-state-policy.md).
|
|
60
60
|
|
|
@@ -68,6 +68,45 @@ snapshot names the same `id` twice. `RetryTracker`'s `maxTracked` must be
|
|
|
68
68
|
at least `1`; `0` throws. `ClaimRegistry`'s `maxCompleted` must be at
|
|
69
69
|
least `1` too — `0` also throws.
|
|
70
70
|
|
|
71
|
+
`SubscriptionTracker` provides synchronous, transport-independent decisions for
|
|
72
|
+
agent-topic joins and the two-topic room subscription transaction. Its opaque
|
|
73
|
+
tickets are JavaScript `bigint` values and must be supplied when recording a
|
|
74
|
+
completion. Failed rollbacks and failed or unknown leaves require explicit
|
|
75
|
+
reconciliation before a fresh claim is allowed.
|
|
76
|
+
|
|
77
|
+
### `SubscriptionTracker` lifecycle
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
import { SubscriptionTracker } from "@band-ai/band-sdk-core";
|
|
81
|
+
|
|
82
|
+
const tracker = new SubscriptionTracker();
|
|
83
|
+
const ticket = tracker.beginRoomSubscribe("room-1");
|
|
84
|
+
if (ticket === undefined) throw new Error("room is not claimable");
|
|
85
|
+
|
|
86
|
+
switch (tracker.recordRoomParticipantsJoinFailed("room-1", ticket, false)) {
|
|
87
|
+
case "rollback_failed":
|
|
88
|
+
if (tracker.roomStatus("room-1") !== "needs_reconciliation") {
|
|
89
|
+
throw new Error("rollback state was not retained");
|
|
90
|
+
}
|
|
91
|
+
tracker.acknowledgeRoomReconciled("room-1");
|
|
92
|
+
const retryTicket = tracker.beginRoomSubscribe("room-1");
|
|
93
|
+
if (retryTicket === undefined) throw new Error("reconciled room is not claimable");
|
|
94
|
+
if (tracker.recordBothRoomTopicsJoined("room-1", retryTicket) !== "subscribed") {
|
|
95
|
+
throw new Error("room did not subscribe");
|
|
96
|
+
}
|
|
97
|
+
const leaveTicket = tracker.unsubscribeRoom("room-1");
|
|
98
|
+
if (leaveTicket === undefined || !tracker.markRoomLeaveComplete("room-1", leaveTicket, "left")) {
|
|
99
|
+
throw new Error("room did not leave");
|
|
100
|
+
}
|
|
101
|
+
break;
|
|
102
|
+
case "subscribed":
|
|
103
|
+
case "join_failed":
|
|
104
|
+
case "rolled_back":
|
|
105
|
+
case "stale":
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
71
110
|
### `validateMemoryTypeForSystem(system, type, traceContext?)`
|
|
72
111
|
|
|
73
112
|
Validates the canonical memory taxonomy — design decisions:
|
package/band_sdk_core.js
CHANGED
|
@@ -348,6 +348,264 @@ class RetryTracker {
|
|
|
348
348
|
if (Symbol.dispose) RetryTracker.prototype[Symbol.dispose] = RetryTracker.prototype.free;
|
|
349
349
|
exports.RetryTracker = RetryTracker;
|
|
350
350
|
|
|
351
|
+
/**
|
|
352
|
+
* Transport-independent subscription decisions for one agent session.
|
|
353
|
+
*/
|
|
354
|
+
class SubscriptionTracker {
|
|
355
|
+
__destroy_into_raw() {
|
|
356
|
+
const ptr = this.__wbg_ptr;
|
|
357
|
+
this.__wbg_ptr = 0;
|
|
358
|
+
SubscriptionTrackerFinalization.unregister(this);
|
|
359
|
+
return ptr;
|
|
360
|
+
}
|
|
361
|
+
free() {
|
|
362
|
+
const ptr = this.__destroy_into_raw();
|
|
363
|
+
wasm.__wbg_subscriptiontracker_free(ptr, 0);
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* @param {any} topic
|
|
367
|
+
* @returns {boolean}
|
|
368
|
+
*/
|
|
369
|
+
acknowledgeAgentTopicReconciled(topic) {
|
|
370
|
+
const ret = wasm.subscriptiontracker_acknowledgeAgentTopicReconciled(this.__wbg_ptr, topic);
|
|
371
|
+
if (ret[2]) {
|
|
372
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
373
|
+
}
|
|
374
|
+
return ret[0] !== 0;
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* @param {any} room_id
|
|
378
|
+
* @returns {boolean}
|
|
379
|
+
*/
|
|
380
|
+
acknowledgeRoomReconciled(room_id) {
|
|
381
|
+
const ret = wasm.subscriptiontracker_acknowledgeRoomReconciled(this.__wbg_ptr, room_id);
|
|
382
|
+
if (ret[2]) {
|
|
383
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
384
|
+
}
|
|
385
|
+
return ret[0] !== 0;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* @param {any} topic
|
|
389
|
+
* @returns {string}
|
|
390
|
+
*/
|
|
391
|
+
agentTopicStatus(topic) {
|
|
392
|
+
const ret = wasm.subscriptiontracker_agentTopicStatus(this.__wbg_ptr, topic);
|
|
393
|
+
if (ret[3]) {
|
|
394
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
395
|
+
}
|
|
396
|
+
return getStringFromWasm0(ret[0], ret[1]);
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* @param {any} topic
|
|
400
|
+
* @returns {bigint | undefined}
|
|
401
|
+
*/
|
|
402
|
+
beginAgentTopicJoin(topic) {
|
|
403
|
+
const ret = wasm.subscriptiontracker_beginAgentTopicJoin(this.__wbg_ptr, topic);
|
|
404
|
+
if (ret[3]) {
|
|
405
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
406
|
+
}
|
|
407
|
+
return ret[0] === 0 ? undefined : BigInt.asUintN(64, ret[1]);
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* @param {any} room_id
|
|
411
|
+
* @returns {bigint | undefined}
|
|
412
|
+
*/
|
|
413
|
+
beginRoomSubscribe(room_id) {
|
|
414
|
+
const ret = wasm.subscriptiontracker_beginRoomSubscribe(this.__wbg_ptr, room_id);
|
|
415
|
+
if (ret[3]) {
|
|
416
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
417
|
+
}
|
|
418
|
+
return ret[0] === 0 ? undefined : BigInt.asUintN(64, ret[1]);
|
|
419
|
+
}
|
|
420
|
+
endSession() {
|
|
421
|
+
wasm.subscriptiontracker_endSession(this.__wbg_ptr);
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* @param {any} topic
|
|
425
|
+
* @param {bigint} ticket
|
|
426
|
+
* @returns {boolean}
|
|
427
|
+
*/
|
|
428
|
+
isAgentTopicClaimCurrent(topic, ticket) {
|
|
429
|
+
const ret = wasm.subscriptiontracker_isAgentTopicClaimCurrent(this.__wbg_ptr, topic, ticket);
|
|
430
|
+
if (ret[2]) {
|
|
431
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
432
|
+
}
|
|
433
|
+
return ret[0] !== 0;
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* @param {any} topic
|
|
437
|
+
* @returns {boolean}
|
|
438
|
+
*/
|
|
439
|
+
isAgentTopicJoined(topic) {
|
|
440
|
+
const ret = wasm.subscriptiontracker_isAgentTopicJoined(this.__wbg_ptr, topic);
|
|
441
|
+
if (ret[2]) {
|
|
442
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
443
|
+
}
|
|
444
|
+
return ret[0] !== 0;
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* @param {any} room_id
|
|
448
|
+
* @param {bigint} ticket
|
|
449
|
+
* @returns {boolean}
|
|
450
|
+
*/
|
|
451
|
+
isRoomClaimCurrent(room_id, ticket) {
|
|
452
|
+
const ret = wasm.subscriptiontracker_isRoomClaimCurrent(this.__wbg_ptr, room_id, ticket);
|
|
453
|
+
if (ret[2]) {
|
|
454
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
455
|
+
}
|
|
456
|
+
return ret[0] !== 0;
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* @param {any} room_id
|
|
460
|
+
* @returns {boolean}
|
|
461
|
+
*/
|
|
462
|
+
isRoomSubscribed(room_id) {
|
|
463
|
+
const ret = wasm.subscriptiontracker_isRoomSubscribed(this.__wbg_ptr, room_id);
|
|
464
|
+
if (ret[2]) {
|
|
465
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
466
|
+
}
|
|
467
|
+
return ret[0] !== 0;
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* @returns {string[]}
|
|
471
|
+
*/
|
|
472
|
+
joinedAgentTopics() {
|
|
473
|
+
const ret = wasm.subscriptiontracker_joinedAgentTopics(this.__wbg_ptr);
|
|
474
|
+
var v1 = getArrayJsValueFromWasm0(ret[0], ret[1]);
|
|
475
|
+
wasm.__wbindgen_free(ret[0], ret[1] * 4, 4);
|
|
476
|
+
return v1;
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* @param {any} topic
|
|
480
|
+
* @returns {bigint | undefined}
|
|
481
|
+
*/
|
|
482
|
+
leaveAgentTopic(topic) {
|
|
483
|
+
const ret = wasm.subscriptiontracker_leaveAgentTopic(this.__wbg_ptr, topic);
|
|
484
|
+
if (ret[3]) {
|
|
485
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
486
|
+
}
|
|
487
|
+
return ret[0] === 0 ? undefined : BigInt.asUintN(64, ret[1]);
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* @param {any} topic
|
|
491
|
+
* @param {bigint} ticket
|
|
492
|
+
* @param {any} outcome
|
|
493
|
+
* @returns {boolean}
|
|
494
|
+
*/
|
|
495
|
+
markAgentTopicLeaveComplete(topic, ticket, outcome) {
|
|
496
|
+
const ret = wasm.subscriptiontracker_markAgentTopicLeaveComplete(this.__wbg_ptr, topic, ticket, outcome);
|
|
497
|
+
if (ret[2]) {
|
|
498
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
499
|
+
}
|
|
500
|
+
return ret[0] !== 0;
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* @param {any} room_id
|
|
504
|
+
* @param {bigint} ticket
|
|
505
|
+
* @param {any} outcome
|
|
506
|
+
* @returns {boolean}
|
|
507
|
+
*/
|
|
508
|
+
markRoomLeaveComplete(room_id, ticket, outcome) {
|
|
509
|
+
const ret = wasm.subscriptiontracker_markRoomLeaveComplete(this.__wbg_ptr, room_id, ticket, outcome);
|
|
510
|
+
if (ret[2]) {
|
|
511
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
512
|
+
}
|
|
513
|
+
return ret[0] !== 0;
|
|
514
|
+
}
|
|
515
|
+
constructor() {
|
|
516
|
+
const ret = wasm.subscriptiontracker_new();
|
|
517
|
+
this.__wbg_ptr = ret;
|
|
518
|
+
SubscriptionTrackerFinalization.register(this, this.__wbg_ptr, this);
|
|
519
|
+
return this;
|
|
520
|
+
}
|
|
521
|
+
onReconnected() {
|
|
522
|
+
wasm.subscriptiontracker_onReconnected(this.__wbg_ptr);
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* @param {any} topic
|
|
526
|
+
* @param {bigint} ticket
|
|
527
|
+
* @param {boolean} joined
|
|
528
|
+
* @returns {boolean}
|
|
529
|
+
*/
|
|
530
|
+
recordAgentTopicJoin(topic, ticket, joined) {
|
|
531
|
+
const ret = wasm.subscriptiontracker_recordAgentTopicJoin(this.__wbg_ptr, topic, ticket, joined);
|
|
532
|
+
if (ret[2]) {
|
|
533
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
534
|
+
}
|
|
535
|
+
return ret[0] !== 0;
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* @param {any} room_id
|
|
539
|
+
* @param {bigint} ticket
|
|
540
|
+
* @returns {string}
|
|
541
|
+
*/
|
|
542
|
+
recordBothRoomTopicsJoined(room_id, ticket) {
|
|
543
|
+
const ret = wasm.subscriptiontracker_recordBothRoomTopicsJoined(this.__wbg_ptr, room_id, ticket);
|
|
544
|
+
if (ret[3]) {
|
|
545
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
546
|
+
}
|
|
547
|
+
return getStringFromWasm0(ret[0], ret[1]);
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* @param {any} room_id
|
|
551
|
+
* @param {bigint} ticket
|
|
552
|
+
* @returns {string}
|
|
553
|
+
*/
|
|
554
|
+
recordChatRoomJoinFailed(room_id, ticket) {
|
|
555
|
+
const ret = wasm.subscriptiontracker_recordChatRoomJoinFailed(this.__wbg_ptr, room_id, ticket);
|
|
556
|
+
if (ret[3]) {
|
|
557
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
558
|
+
}
|
|
559
|
+
return getStringFromWasm0(ret[0], ret[1]);
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* @param {any} room_id
|
|
563
|
+
* @param {bigint} ticket
|
|
564
|
+
* @param {boolean} chatRoomLeft
|
|
565
|
+
* @returns {string}
|
|
566
|
+
*/
|
|
567
|
+
recordRoomParticipantsJoinFailed(room_id, ticket, chatRoomLeft) {
|
|
568
|
+
const ret = wasm.subscriptiontracker_recordRoomParticipantsJoinFailed(this.__wbg_ptr, room_id, ticket, chatRoomLeft);
|
|
569
|
+
if (ret[3]) {
|
|
570
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
571
|
+
}
|
|
572
|
+
return getStringFromWasm0(ret[0], ret[1]);
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* @param {any} room_id
|
|
576
|
+
* @returns {string}
|
|
577
|
+
*/
|
|
578
|
+
roomStatus(room_id) {
|
|
579
|
+
const ret = wasm.subscriptiontracker_roomStatus(this.__wbg_ptr, room_id);
|
|
580
|
+
if (ret[3]) {
|
|
581
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
582
|
+
}
|
|
583
|
+
return getStringFromWasm0(ret[0], ret[1]);
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* @returns {string[]}
|
|
587
|
+
*/
|
|
588
|
+
subscribedRoomIds() {
|
|
589
|
+
const ret = wasm.subscriptiontracker_subscribedRoomIds(this.__wbg_ptr);
|
|
590
|
+
var v1 = getArrayJsValueFromWasm0(ret[0], ret[1]);
|
|
591
|
+
wasm.__wbindgen_free(ret[0], ret[1] * 4, 4);
|
|
592
|
+
return v1;
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* @param {any} room_id
|
|
596
|
+
* @returns {bigint | undefined}
|
|
597
|
+
*/
|
|
598
|
+
unsubscribeRoom(room_id) {
|
|
599
|
+
const ret = wasm.subscriptiontracker_unsubscribeRoom(this.__wbg_ptr, room_id);
|
|
600
|
+
if (ret[3]) {
|
|
601
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
602
|
+
}
|
|
603
|
+
return ret[0] === 0 ? undefined : BigInt.asUintN(64, ret[1]);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
if (Symbol.dispose) SubscriptionTracker.prototype[Symbol.dispose] = SubscriptionTracker.prototype.free;
|
|
607
|
+
exports.SubscriptionTracker = SubscriptionTracker;
|
|
608
|
+
|
|
351
609
|
/**
|
|
352
610
|
* Validate and normalize an inbound platform event payload.
|
|
353
611
|
*
|
|
@@ -650,6 +908,9 @@ const ParticipantRosterFinalization = (typeof FinalizationRegistry === 'undefine
|
|
|
650
908
|
const RetryTrackerFinalization = (typeof FinalizationRegistry === 'undefined')
|
|
651
909
|
? { register: () => {}, unregister: () => {} }
|
|
652
910
|
: new FinalizationRegistry(ptr => wasm.__wbg_retrytracker_free(ptr, 1));
|
|
911
|
+
const SubscriptionTrackerFinalization = (typeof FinalizationRegistry === 'undefined')
|
|
912
|
+
? { register: () => {}, unregister: () => {} }
|
|
913
|
+
: new FinalizationRegistry(ptr => wasm.__wbg_subscriptiontracker_free(ptr, 1));
|
|
653
914
|
|
|
654
915
|
function addToExternrefTable0(obj) {
|
|
655
916
|
const idx = wasm.__externref_table_alloc();
|
package/band_sdk_core_bg.wasm
CHANGED
|
Binary file
|
package/index.d.ts
CHANGED
|
@@ -145,3 +145,53 @@ export class ParticipantRoster {
|
|
|
145
145
|
changed(): boolean;
|
|
146
146
|
markSent(): void;
|
|
147
147
|
}
|
|
148
|
+
|
|
149
|
+
export type RoomSubscribeResult =
|
|
150
|
+
| "subscribed"
|
|
151
|
+
| "join_failed"
|
|
152
|
+
| "rolled_back"
|
|
153
|
+
| "rollback_failed"
|
|
154
|
+
| "stale";
|
|
155
|
+
|
|
156
|
+
export type RoomStatus =
|
|
157
|
+
| "absent"
|
|
158
|
+
| "pending"
|
|
159
|
+
| "subscribed"
|
|
160
|
+
| "leaving"
|
|
161
|
+
| "needs_reconciliation";
|
|
162
|
+
|
|
163
|
+
export type AgentTopicStatus =
|
|
164
|
+
| "absent"
|
|
165
|
+
| "pending"
|
|
166
|
+
| "joined"
|
|
167
|
+
| "leaving"
|
|
168
|
+
| "needs_reconciliation";
|
|
169
|
+
|
|
170
|
+
export type LeaveOutcome = "left" | "failed" | "unknown";
|
|
171
|
+
|
|
172
|
+
/** Transport-independent subscription decisions for one agent session. */
|
|
173
|
+
export class SubscriptionTracker {
|
|
174
|
+
constructor();
|
|
175
|
+
beginRoomSubscribe(roomId: string): bigint | undefined;
|
|
176
|
+
recordChatRoomJoinFailed(roomId: string, ticket: bigint): RoomSubscribeResult;
|
|
177
|
+
recordBothRoomTopicsJoined(roomId: string, ticket: bigint): RoomSubscribeResult;
|
|
178
|
+
recordRoomParticipantsJoinFailed(roomId: string, ticket: bigint, chatRoomLeft: boolean): RoomSubscribeResult;
|
|
179
|
+
isRoomSubscribed(roomId: string): boolean;
|
|
180
|
+
isRoomClaimCurrent(roomId: string, ticket: bigint): boolean;
|
|
181
|
+
roomStatus(roomId: string): RoomStatus;
|
|
182
|
+
unsubscribeRoom(roomId: string): bigint | undefined;
|
|
183
|
+
markRoomLeaveComplete(roomId: string, ticket: bigint, outcome: LeaveOutcome): boolean;
|
|
184
|
+
acknowledgeRoomReconciled(roomId: string): boolean;
|
|
185
|
+
subscribedRoomIds(): string[];
|
|
186
|
+
onReconnected(): void;
|
|
187
|
+
endSession(): void;
|
|
188
|
+
beginAgentTopicJoin(topic: string): bigint | undefined;
|
|
189
|
+
recordAgentTopicJoin(topic: string, ticket: bigint, joined: boolean): boolean;
|
|
190
|
+
isAgentTopicJoined(topic: string): boolean;
|
|
191
|
+
isAgentTopicClaimCurrent(topic: string, ticket: bigint): boolean;
|
|
192
|
+
agentTopicStatus(topic: string): AgentTopicStatus;
|
|
193
|
+
leaveAgentTopic(topic: string): bigint | undefined;
|
|
194
|
+
markAgentTopicLeaveComplete(topic: string, ticket: bigint, outcome: LeaveOutcome): boolean;
|
|
195
|
+
acknowledgeAgentTopicReconciled(topic: string): boolean;
|
|
196
|
+
joinedAgentTopics(): string[];
|
|
197
|
+
}
|