@data-club/ai-hub-server 0.0.1
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/auth/argon2.d.ts +72 -0
- package/dist/auth/argon2.d.ts.map +1 -0
- package/dist/auth/argon2.js +145 -0
- package/dist/auth/argon2.js.map +1 -0
- package/dist/auth/encryption.d.ts +52 -0
- package/dist/auth/encryption.d.ts.map +1 -0
- package/dist/auth/encryption.js +98 -0
- package/dist/auth/encryption.js.map +1 -0
- package/dist/auth/jwt.d.ts +133 -0
- package/dist/auth/jwt.d.ts.map +1 -0
- package/dist/auth/jwt.js +147 -0
- package/dist/auth/jwt.js.map +1 -0
- package/dist/auth/middleware.d.ts +101 -0
- package/dist/auth/middleware.d.ts.map +1 -0
- package/dist/auth/middleware.js +161 -0
- package/dist/auth/middleware.js.map +1 -0
- package/dist/auth/passwordPolicy.d.ts +72 -0
- package/dist/auth/passwordPolicy.d.ts.map +1 -0
- package/dist/auth/passwordPolicy.js +88 -0
- package/dist/auth/passwordPolicy.js.map +1 -0
- package/dist/auth/roleRules.d.ts +200 -0
- package/dist/auth/roleRules.d.ts.map +1 -0
- package/dist/auth/roleRules.js +365 -0
- package/dist/auth/roleRules.js.map +1 -0
- package/dist/auth/userView.d.ts +55 -0
- package/dist/auth/userView.d.ts.map +1 -0
- package/dist/auth/userView.js +77 -0
- package/dist/auth/userView.js.map +1 -0
- package/dist/bootstrap.d.ts +104 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/bootstrap.js +160 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/db/connection.d.ts +39 -0
- package/dist/db/connection.d.ts.map +1 -0
- package/dist/db/connection.js +62 -0
- package/dist/db/connection.js.map +1 -0
- package/dist/db/migrate.d.ts +31 -0
- package/dist/db/migrate.d.ts.map +1 -0
- package/dist/db/migrate.js +197 -0
- package/dist/db/migrate.js.map +1 -0
- package/dist/db/schema.d.ts +1902 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +662 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/db/seed.d.ts +92 -0
- package/dist/db/seed.d.ts.map +1 -0
- package/dist/db/seed.js +160 -0
- package/dist/db/seed.js.map +1 -0
- package/dist/handlers/fetch.d.ts +89 -0
- package/dist/handlers/fetch.d.ts.map +1 -0
- package/dist/handlers/fetch.js +173 -0
- package/dist/handlers/fetch.js.map +1 -0
- package/dist/handlers/nextjs.d.ts +40 -0
- package/dist/handlers/nextjs.d.ts.map +1 -0
- package/dist/handlers/nextjs.js +42 -0
- package/dist/handlers/nextjs.js.map +1 -0
- package/dist/handlers/responses.d.ts +46 -0
- package/dist/handlers/responses.d.ts.map +1 -0
- package/dist/handlers/responses.js +74 -0
- package/dist/handlers/responses.js.map +1 -0
- package/dist/handlers/routeTable.d.ts +21 -0
- package/dist/handlers/routeTable.d.ts.map +1 -0
- package/dist/handlers/routeTable.js +133 -0
- package/dist/handlers/routeTable.js.map +1 -0
- package/dist/handlers/router.d.ts +37 -0
- package/dist/handlers/router.d.ts.map +1 -0
- package/dist/handlers/router.js +82 -0
- package/dist/handlers/router.js.map +1 -0
- package/dist/handlers/sse.d.ts +38 -0
- package/dist/handlers/sse.d.ts.map +1 -0
- package/dist/handlers/sse.js +52 -0
- package/dist/handlers/sse.js.map +1 -0
- package/dist/handlers/types.d.ts +96 -0
- package/dist/handlers/types.d.ts.map +1 -0
- package/dist/handlers/types.js +14 -0
- package/dist/handlers/types.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/letta/client.d.ts +355 -0
- package/dist/letta/client.d.ts.map +1 -0
- package/dist/letta/client.js +529 -0
- package/dist/letta/client.js.map +1 -0
- package/dist/letta/eventTranslator.d.ts +166 -0
- package/dist/letta/eventTranslator.d.ts.map +1 -0
- package/dist/letta/eventTranslator.js +532 -0
- package/dist/letta/eventTranslator.js.map +1 -0
- package/dist/letta/index.d.ts +13 -0
- package/dist/letta/index.d.ts.map +1 -0
- package/dist/letta/index.js +12 -0
- package/dist/letta/index.js.map +1 -0
- package/dist/letta/modelSettings.d.ts +176 -0
- package/dist/letta/modelSettings.d.ts.map +1 -0
- package/dist/letta/modelSettings.js +314 -0
- package/dist/letta/modelSettings.js.map +1 -0
- package/dist/letta/promptWrapping.d.ts +141 -0
- package/dist/letta/promptWrapping.d.ts.map +1 -0
- package/dist/letta/promptWrapping.js +213 -0
- package/dist/letta/promptWrapping.js.map +1 -0
- package/dist/letta/sandbox.d.ts +100 -0
- package/dist/letta/sandbox.d.ts.map +1 -0
- package/dist/letta/sandbox.js +151 -0
- package/dist/letta/sandbox.js.map +1 -0
- package/dist/letta/settingsFileSeed.d.ts +146 -0
- package/dist/letta/settingsFileSeed.d.ts.map +1 -0
- package/dist/letta/settingsFileSeed.js +177 -0
- package/dist/letta/settingsFileSeed.js.map +1 -0
- package/dist/letta/subprocessThrottle.d.ts +151 -0
- package/dist/letta/subprocessThrottle.d.ts.map +1 -0
- package/dist/letta/subprocessThrottle.js +195 -0
- package/dist/letta/subprocessThrottle.js.map +1 -0
- package/dist/letta/tpmRecovery.d.ts +202 -0
- package/dist/letta/tpmRecovery.d.ts.map +1 -0
- package/dist/letta/tpmRecovery.js +314 -0
- package/dist/letta/tpmRecovery.js.map +1 -0
- package/dist/letta/types.d.ts +54 -0
- package/dist/letta/types.d.ts.map +1 -0
- package/dist/letta/types.js +16 -0
- package/dist/letta/types.js.map +1 -0
- package/dist/observability/logger.d.ts +48 -0
- package/dist/observability/logger.d.ts.map +1 -0
- package/dist/observability/logger.js +81 -0
- package/dist/observability/logger.js.map +1 -0
- package/dist/observability/metrics.d.ts +53 -0
- package/dist/observability/metrics.d.ts.map +1 -0
- package/dist/observability/metrics.js +92 -0
- package/dist/observability/metrics.js.map +1 -0
- package/dist/routes/admin/agents.d.ts +63 -0
- package/dist/routes/admin/agents.d.ts.map +1 -0
- package/dist/routes/admin/agents.js +461 -0
- package/dist/routes/admin/agents.js.map +1 -0
- package/dist/routes/admin/rotatingMessages.d.ts +51 -0
- package/dist/routes/admin/rotatingMessages.d.ts.map +1 -0
- package/dist/routes/admin/rotatingMessages.js +292 -0
- package/dist/routes/admin/rotatingMessages.js.map +1 -0
- package/dist/routes/admin/sessions.d.ts +61 -0
- package/dist/routes/admin/sessions.d.ts.map +1 -0
- package/dist/routes/admin/sessions.js +232 -0
- package/dist/routes/admin/sessions.js.map +1 -0
- package/dist/routes/admin/settings.d.ts +110 -0
- package/dist/routes/admin/settings.d.ts.map +1 -0
- package/dist/routes/admin/settings.js +401 -0
- package/dist/routes/admin/settings.js.map +1 -0
- package/dist/routes/admin/users.d.ts +115 -0
- package/dist/routes/admin/users.d.ts.map +1 -0
- package/dist/routes/admin/users.js +374 -0
- package/dist/routes/admin/users.js.map +1 -0
- package/dist/routes/agents.d.ts +30 -0
- package/dist/routes/agents.d.ts.map +1 -0
- package/dist/routes/agents.js +55 -0
- package/dist/routes/agents.js.map +1 -0
- package/dist/routes/auth.d.ts +121 -0
- package/dist/routes/auth.d.ts.map +1 -0
- package/dist/routes/auth.js +422 -0
- package/dist/routes/auth.js.map +1 -0
- package/dist/routes/chat.d.ts +97 -0
- package/dist/routes/chat.d.ts.map +1 -0
- package/dist/routes/chat.js +484 -0
- package/dist/routes/chat.js.map +1 -0
- package/dist/routes/featureToggles.d.ts +34 -0
- package/dist/routes/featureToggles.d.ts.map +1 -0
- package/dist/routes/featureToggles.js +47 -0
- package/dist/routes/featureToggles.js.map +1 -0
- package/dist/routes/health.d.ts +24 -0
- package/dist/routes/health.d.ts.map +1 -0
- package/dist/routes/health.js +37 -0
- package/dist/routes/health.js.map +1 -0
- package/dist/routes/metrics.d.ts +35 -0
- package/dist/routes/metrics.d.ts.map +1 -0
- package/dist/routes/metrics.js +106 -0
- package/dist/routes/metrics.js.map +1 -0
- package/dist/routes/sessions.d.ts +161 -0
- package/dist/routes/sessions.d.ts.map +1 -0
- package/dist/routes/sessions.js +1501 -0
- package/dist/routes/sessions.js.map +1 -0
- package/dist/routes/stubs.d.ts +25 -0
- package/dist/routes/stubs.d.ts.map +1 -0
- package/dist/routes/stubs.js +25 -0
- package/dist/routes/stubs.js.map +1 -0
- package/dist/state/cron.d.ts +58 -0
- package/dist/state/cron.d.ts.map +1 -0
- package/dist/state/cron.js +160 -0
- package/dist/state/cron.js.map +1 -0
- package/dist/state/rotationRunner.d.ts +96 -0
- package/dist/state/rotationRunner.d.ts.map +1 -0
- package/dist/state/rotationRunner.js +246 -0
- package/dist/state/rotationRunner.js.map +1 -0
- package/dist/state/rotationScheduler.d.ts +76 -0
- package/dist/state/rotationScheduler.d.ts.map +1 -0
- package/dist/state/rotationScheduler.js +124 -0
- package/dist/state/rotationScheduler.js.map +1 -0
- package/dist/state/turnRegistry.d.ts +95 -0
- package/dist/state/turnRegistry.d.ts.map +1 -0
- package/dist/state/turnRegistry.js +149 -0
- package/dist/state/turnRegistry.js.map +1 -0
- package/dist/state/turnRunner.d.ts +134 -0
- package/dist/state/turnRunner.d.ts.map +1 -0
- package/dist/state/turnRunner.js +476 -0
- package/dist/state/turnRunner.js.map +1 -0
- package/package.json +47 -0
- package/src/auth/argon2.ts +152 -0
- package/src/auth/encryption.ts +110 -0
- package/src/auth/jwt.ts +217 -0
- package/src/auth/middleware.ts +250 -0
- package/src/auth/passwordPolicy.ts +99 -0
- package/src/auth/roleRules.ts +497 -0
- package/src/auth/userView.ts +88 -0
- package/src/bootstrap.ts +254 -0
- package/src/db/connection.ts +75 -0
- package/src/db/migrate.ts +212 -0
- package/src/db/schema.ts +750 -0
- package/src/db/seed.ts +236 -0
- package/src/handlers/fetch.ts +251 -0
- package/src/handlers/nextjs.ts +49 -0
- package/src/handlers/responses.ts +95 -0
- package/src/handlers/routeTable.ts +188 -0
- package/src/handlers/router.ts +96 -0
- package/src/handlers/sse.ts +55 -0
- package/src/handlers/types.ts +104 -0
- package/src/index.ts +60 -0
- package/src/letta/client.ts +860 -0
- package/src/letta/eventTranslator.ts +667 -0
- package/src/letta/index.ts +46 -0
- package/src/letta/lettaCliShim.mjs +40 -0
- package/src/letta/sandbox.ts +167 -0
- package/src/letta/settingsFileSeed.ts +254 -0
- package/src/letta/subprocessThrottle.ts +251 -0
- package/src/letta/types.ts +65 -0
- package/src/observability/logger.ts +103 -0
- package/src/observability/metrics.ts +114 -0
- package/src/routes/admin/agents.ts +574 -0
- package/src/routes/admin/rotatingMessages.ts +351 -0
- package/src/routes/admin/sessions.ts +283 -0
- package/src/routes/admin/settings.ts +463 -0
- package/src/routes/admin/users.ts +455 -0
- package/src/routes/agents.ts +66 -0
- package/src/routes/auth.ts +513 -0
- package/src/routes/chat.ts +534 -0
- package/src/routes/featureToggles.ts +52 -0
- package/src/routes/health.ts +44 -0
- package/src/routes/metrics.ts +111 -0
- package/src/routes/sessions.ts +1878 -0
- package/src/state/cron.ts +179 -0
- package/src/state/rotationRunner.ts +326 -0
- package/src/state/rotationScheduler.ts +164 -0
- package/src/state/turnRegistry.ts +210 -0
- package/src/state/turnRunner.ts +588 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory broadcaster for live turn streams.
|
|
3
|
+
*
|
|
4
|
+
* Every active turn has at most one writer (the runner) and zero-or-more
|
|
5
|
+
* subscribers (the original `POST /chat` connection + every
|
|
6
|
+
* `GET /chat/:turn_id/events?from_seq=N` resumption connection still
|
|
7
|
+
* running while the turn is live).
|
|
8
|
+
*
|
|
9
|
+
* Persistence lives in `turn_events` (§11) — the registry only handles the
|
|
10
|
+
* **live attach** part of resumption. The first half of a resumption read
|
|
11
|
+
* (replay from `from_seq`) is a plain DB query.
|
|
12
|
+
*
|
|
13
|
+
* The registry is process-local — this matches the single-customer
|
|
14
|
+
* deployment model (§1). When ai-hub scales to multiple replicas in a
|
|
15
|
+
* v1.x release, this gets a Redis-backed implementation behind the same
|
|
16
|
+
* interface; the wire protocol (§9) and the resumption contract (§6.3.2)
|
|
17
|
+
* stay unchanged.
|
|
18
|
+
*
|
|
19
|
+
* @see SPECIFICATIONS.md §6.3.2 — resumption endpoint
|
|
20
|
+
* @see SPECIFICATIONS.md §6.6 — server-authoritative state machine
|
|
21
|
+
* @see SPECIFICATIONS.md §11 — `turn_events` table
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import type { AIHubEvent } from "@data-club/ai-hub";
|
|
25
|
+
|
|
26
|
+
/** Callback signature for a live subscriber. */
|
|
27
|
+
export type TurnEventListener = (event: AIHubEvent) => void;
|
|
28
|
+
|
|
29
|
+
/** Returned by `subscribe()` so the caller can unsubscribe. */
|
|
30
|
+
export type Unsubscribe = () => void;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Per-turn live channel. The runner calls `publish()` once per event it
|
|
34
|
+
* emits; subscribers receive every event from the point of subscription
|
|
35
|
+
* onward. When the runner calls `close()`, every remaining subscriber's
|
|
36
|
+
* stream gets `null` so it knows to flush + close its SSE writer.
|
|
37
|
+
*/
|
|
38
|
+
interface ActiveTurn {
|
|
39
|
+
/** Highest-seen seq on this channel (informational; the runner is the source of truth). */
|
|
40
|
+
lastSeq: number;
|
|
41
|
+
/** Whether the runner has called `close()`. */
|
|
42
|
+
closed: boolean;
|
|
43
|
+
/** Active listeners. */
|
|
44
|
+
listeners: Set<TurnEventListener>;
|
|
45
|
+
/** Listeners notified once when the turn closes. */
|
|
46
|
+
closeListeners: Set<() => void>;
|
|
47
|
+
/**
|
|
48
|
+
* AbortController exposed to the runner — fired by
|
|
49
|
+
* `requestTurnCancellation(turnId)` so a separate `POST /chat/:id/cancel`
|
|
50
|
+
* request can short-circuit the in-process runner without having to
|
|
51
|
+
* abort the runner's originating request signal (which lives on a
|
|
52
|
+
* different `Request` instance). The runner translates this into a
|
|
53
|
+
* `handle.abort()` call on the spawned Letta Code subprocess (which
|
|
54
|
+
* sends an `interrupt` control to the CLI).
|
|
55
|
+
*
|
|
56
|
+
* Pre-migration this also drove an `agents.messages.cancel({run_ids})`
|
|
57
|
+
* call on the Letta server side via the captured `lettaRunId`. Post-
|
|
58
|
+
* migration the run-id tracking is gone — the SDK abstracts it — and
|
|
59
|
+
* cancel is `handle.abort()` only. See migration plan §4.2.
|
|
60
|
+
*/
|
|
61
|
+
cancelController: AbortController;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Process-local map of live turn channels. The map prunes a channel on
|
|
66
|
+
* close as soon as every subscriber has unsubscribed (or immediately if
|
|
67
|
+
* no subscribers are attached).
|
|
68
|
+
*/
|
|
69
|
+
const channels = new Map<string, ActiveTurn>();
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Begins a new live turn channel.
|
|
73
|
+
*
|
|
74
|
+
* The runner calls this when it inserts the `turn` row, before it starts
|
|
75
|
+
* pumping events. Returns an opaque `TurnPublisher` the runner uses to
|
|
76
|
+
* publish + close.
|
|
77
|
+
*
|
|
78
|
+
* @param turnId - the freshly-created turn id.
|
|
79
|
+
* @returns the publisher handle.
|
|
80
|
+
*/
|
|
81
|
+
export function openTurnChannel(turnId: string): TurnPublisher {
|
|
82
|
+
if (channels.has(turnId)) {
|
|
83
|
+
throw new Error(`Turn ${turnId} already has an open channel.`);
|
|
84
|
+
}
|
|
85
|
+
const channel: ActiveTurn = {
|
|
86
|
+
lastSeq: -1,
|
|
87
|
+
closed: false,
|
|
88
|
+
listeners: new Set(),
|
|
89
|
+
closeListeners: new Set(),
|
|
90
|
+
cancelController: new AbortController(),
|
|
91
|
+
};
|
|
92
|
+
channels.set(turnId, channel);
|
|
93
|
+
return {
|
|
94
|
+
cancelSignal: channel.cancelController.signal,
|
|
95
|
+
publish(event: AIHubEvent) {
|
|
96
|
+
channel.lastSeq = event.seq;
|
|
97
|
+
for (const listener of channel.listeners) {
|
|
98
|
+
try {
|
|
99
|
+
listener(event);
|
|
100
|
+
} catch {
|
|
101
|
+
/* swallow — a misbehaving listener cannot break the channel */
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
close() {
|
|
106
|
+
if (channel.closed) return;
|
|
107
|
+
channel.closed = true;
|
|
108
|
+
for (const cb of channel.closeListeners) {
|
|
109
|
+
try {
|
|
110
|
+
cb();
|
|
111
|
+
} catch {
|
|
112
|
+
/* ignored */
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
channel.closeListeners.clear();
|
|
116
|
+
// Drop the channel once every subscriber unsubscribed. If nobody is
|
|
117
|
+
// listening at close time, prune immediately.
|
|
118
|
+
if (channel.listeners.size === 0) {
|
|
119
|
+
channels.delete(turnId);
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Subscribes to a live turn channel.
|
|
127
|
+
*
|
|
128
|
+
* Returns `null` when the turn is not active (either never opened or
|
|
129
|
+
* already closed) — the caller should fall back to replaying persisted
|
|
130
|
+
* events from `turn_events` instead.
|
|
131
|
+
*
|
|
132
|
+
* @param turnId - the turn id to attach to.
|
|
133
|
+
* @param listener - called once per event (with `seq` already assigned).
|
|
134
|
+
* @param onClose - called once when the channel closes (after final event).
|
|
135
|
+
* @returns an unsubscribe function, or `null` when the channel is closed.
|
|
136
|
+
*/
|
|
137
|
+
export function subscribeToTurn(
|
|
138
|
+
turnId: string,
|
|
139
|
+
listener: TurnEventListener,
|
|
140
|
+
onClose: () => void,
|
|
141
|
+
): Unsubscribe | null {
|
|
142
|
+
const channel = channels.get(turnId);
|
|
143
|
+
if (!channel || channel.closed) return null;
|
|
144
|
+
channel.listeners.add(listener);
|
|
145
|
+
channel.closeListeners.add(onClose);
|
|
146
|
+
return () => {
|
|
147
|
+
channel.listeners.delete(listener);
|
|
148
|
+
channel.closeListeners.delete(onClose);
|
|
149
|
+
if (channel.closed && channel.listeners.size === 0) {
|
|
150
|
+
channels.delete(turnId);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Returns `true` when the turn has an open channel right now.
|
|
157
|
+
*
|
|
158
|
+
* The chat handler uses this to disambiguate "turn is in flight" from
|
|
159
|
+
* "turn completed long ago" without having to query the DB twice.
|
|
160
|
+
*/
|
|
161
|
+
export function isTurnLive(turnId: string): boolean {
|
|
162
|
+
const channel = channels.get(turnId);
|
|
163
|
+
return !!channel && !channel.closed;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Test-only utility — wipes the registry so tests can isolate from each
|
|
168
|
+
* other. Production code never calls this.
|
|
169
|
+
*/
|
|
170
|
+
export function _resetTurnRegistryForTests(): void {
|
|
171
|
+
channels.clear();
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* The runner's handle on a live channel. Opaque on purpose — the runner
|
|
176
|
+
* is the only writer.
|
|
177
|
+
*/
|
|
178
|
+
export interface TurnPublisher {
|
|
179
|
+
/**
|
|
180
|
+
* AbortSignal that fires when a separate `POST /chat/:id/cancel`
|
|
181
|
+
* request calls `requestTurnCancellation(turnId)`. The runner listens
|
|
182
|
+
* to this in addition to the originating request's signal.
|
|
183
|
+
*/
|
|
184
|
+
cancelSignal: AbortSignal;
|
|
185
|
+
/** Push one event to every current subscriber. */
|
|
186
|
+
publish(event: AIHubEvent): void;
|
|
187
|
+
/** Mark the channel closed. After this, `subscribeToTurn` returns null. */
|
|
188
|
+
close(): void;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Triggers cancellation of the named turn. The runner is expected to
|
|
193
|
+
* have wired its run to the publisher's `cancelSignal`; firing it from
|
|
194
|
+
* here aborts the upstream Letta call and short-circuits the loop.
|
|
195
|
+
*
|
|
196
|
+
* Idempotent: calling on a closed / unknown turn is a no-op. The
|
|
197
|
+
* `POST /chat/:id/cancel` route's user-facing 200 response covers
|
|
198
|
+
* race-conditions where the turn terminated between the request and
|
|
199
|
+
* this call.
|
|
200
|
+
*
|
|
201
|
+
* @param turnId - the turn to cancel.
|
|
202
|
+
* @returns `true` if the signal was fired, `false` if the channel is
|
|
203
|
+
* closed or unknown.
|
|
204
|
+
*/
|
|
205
|
+
export function requestTurnCancellation(turnId: string): boolean {
|
|
206
|
+
const channel = channels.get(turnId);
|
|
207
|
+
if (!channel || channel.closed) return false;
|
|
208
|
+
channel.cancelController.abort();
|
|
209
|
+
return true;
|
|
210
|
+
}
|