@workerdeck/server 0.15.0 → 0.16.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/build/index.d.mts CHANGED
@@ -1,40 +1,45 @@
1
1
  import { IncomingMessage, Server, ServerResponse } from "node:http";
2
2
  import { AttachmentInput, BridgeAnswer, BrowserBridgeExecutor, ClaudeAuthProbe, EngineAdapter, EngineSessionOptions, HostToolDefinition, LanguageModel, McpConnection, ParkedExecution, Runner, RunnerSnapshot, SessionRunnerConfig, ToolExecutionResult, ToolExecutor, ToolSet } from "@workerdeck/core";
3
3
  import { JobQueue, QueueAdapter } from "@workerdeck/queue";
4
- import { CreateSessionRequest, JobEvent, MessageAttachment, ProfileEngine, ProfileInfo, ProviderConfig, SdkSessionSummary, ServerFrame, SessionCapability, SessionInfo, SessionNotification, SessionWebhookConfig } from "@workerdeck/protocol";
4
+ import { CreateSessionRequest, JobEvent, MessageAttachment, ProfileEngine, ProfileInfo, ProfileUsage, ProviderConfig, SdkSessionSummary, ServerFrame, SessionCapability, SessionInfo, SessionNotification, SessionWebhookConfig } from "@workerdeck/protocol";
5
5
 
6
- //#region src/registry.d.ts
7
- type SessionRegistryOptions = {
8
- /**
9
- * Called once per runner as it enters the table, before it starts — the one
10
- * seam every path goes through (create, prepare, adopt, and the rebuild of a
11
- * parked session), which is what a watcher that must not miss a session needs.
12
- */
13
- onRegister?: (runner: Runner) => void;
6
+ //#region src/services/bridge.d.ts
7
+ type BridgeHubOptions = {
8
+ /** How long a bridged call may stay unanswered before it fails. Default 60000. */timeoutMs?: number;
9
+ /** Called when a bridged execution reaches a terminal result — the host feeds
10
+ * it back into the runner's loop. */
11
+ onResult?: (sessionId: string, executionId: string, result: ToolExecutionResult) => void;
14
12
  };
15
- /** In-memory session table. Terminal sessions stay listed until removed or the process exits. */
16
- declare class SessionRegistry {
13
+ /**
14
+ * Routes tool executions between a session and the browser tabs attached to it.
15
+ *
16
+ * A session may have several clients attached (dashboard plus embedded panel);
17
+ * the bridge asks the **first attached** one, which is the closest thing to "the
18
+ * client driving this session". If none is attached, dispatch fails fast rather
19
+ * than hanging — an autonomous job simply never bridges, it uses the server
20
+ * executor instead.
21
+ */
22
+ declare class BridgeHub {
17
23
  #private;
18
- constructor(options?: SessionRegistryOptions);
19
- create(config: SessionRunnerConfig): Runner;
20
- /** Build and list a Claude-engine runner without starting it, so watchers can
21
- * subscribe first. Call `start()` once they have. */
22
- prepare(config: SessionRunnerConfig): Runner;
23
- /** Register an already-built runner (a non-Claude engine) and start it. */
24
- adopt(runner: Runner): Runner;
25
- /** List a runner without starting it — for a rehydrated session, whose watchers
26
- * must be subscribed before it comes back up. */
27
- register(runner: Runner): Runner;
28
- get(id: string): Runner | undefined;
29
- list(): SessionInfo[];
30
- remove(id: string): boolean;
31
- /** Drop a runner WITHOUT closing it: the session isn't ending, it parked and
32
- * lives on in its snapshot. Closing here would tell every client it was over. */
33
- evict(id: string): boolean;
34
- closeAll(): void;
24
+ constructor(options?: BridgeHubOptions);
25
+ /** The executor to hand a runner for this session. Created on first use and
26
+ * reused, so results routed back always reach the same pending table. */
27
+ executorFor(sessionId: string): BrowserBridgeExecutor;
28
+ /** How many clients are watching this session. Parking consults it: a session
29
+ * someone is watching stays live. */
30
+ attachedCount(sessionId: string): number;
31
+ /** Register an attached client. Returns a detach function. */
32
+ attach(sessionId: string, send: (frame: ServerFrame) => void): () => void;
33
+ /**
34
+ * Deliver a client's answer to a bridged call. Returns false when the id is
35
+ * unknown or already settled — late and duplicate answers are ignored.
36
+ */
37
+ resolve(sessionId: string, executionId: string, answer: BridgeAnswer): boolean;
38
+ /** Drop a session's bridge, failing anything still in flight. */
39
+ remove(sessionId: string): void;
35
40
  }
36
41
  //#endregion
37
- //#region src/notifications.d.ts
42
+ //#region src/services/notifications.d.ts
38
43
  type SessionNotificationOptions = {
39
44
  /** POST target for every notification. */webhook?: SessionWebhookConfig;
40
45
  /** Local observer, invoked for every notification whether or not a webhook is
@@ -73,43 +78,38 @@ declare class SessionNotifier {
73
78
  watch(runner: Runner, afterSeq?: number): void;
74
79
  }
75
80
  //#endregion
76
- //#region src/bridge.d.ts
77
- type BridgeHubOptions = {
78
- /** How long a bridged call may stay unanswered before it fails. Default 60000. */timeoutMs?: number;
79
- /** Called when a bridged execution reaches a terminal result — the host feeds
80
- * it back into the runner's loop. */
81
- onResult?: (sessionId: string, executionId: string, result: ToolExecutionResult) => void;
82
- };
83
- /**
84
- * Routes tool executions between a session and the browser tabs attached to it.
85
- *
86
- * A session may have several clients attached (dashboard plus embedded panel);
87
- * the bridge asks the **first attached** one, which is the closest thing to "the
88
- * client driving this session". If none is attached, dispatch fails fast rather
89
- * than hanging — an autonomous job simply never bridges, it uses the server
90
- * executor instead.
91
- */
92
- declare class BridgeHub {
93
- #private;
94
- constructor(options?: BridgeHubOptions);
95
- /** The executor to hand a runner for this session. Created on first use and
96
- * reused, so results routed back always reach the same pending table. */
97
- executorFor(sessionId: string): BrowserBridgeExecutor;
98
- /** How many clients are watching this session. Parking consults it: a session
99
- * someone is watching stays live. */
100
- attachedCount(sessionId: string): number;
101
- /** Register an attached client. Returns a detach function. */
102
- attach(sessionId: string, send: (frame: ServerFrame) => void): () => void;
81
+ //#region src/services/registry.d.ts
82
+ type SessionRegistryOptions = {
103
83
  /**
104
- * Deliver a client's answer to a bridged call. Returns false when the id is
105
- * unknown or already settled late and duplicate answers are ignored.
84
+ * Called once per runner as it enters the table, before it starts — the one
85
+ * seam every path goes through (create, prepare, adopt, and the rebuild of a
86
+ * parked session), which is what a watcher that must not miss a session needs.
106
87
  */
107
- resolve(sessionId: string, executionId: string, answer: BridgeAnswer): boolean;
108
- /** Drop a session's bridge, failing anything still in flight. */
109
- remove(sessionId: string): void;
88
+ onRegister?: (runner: Runner) => void;
89
+ };
90
+ /** In-memory session table. Terminal sessions stay listed until removed or the process exits. */
91
+ declare class SessionRegistry {
92
+ #private;
93
+ constructor(options?: SessionRegistryOptions);
94
+ create(config: SessionRunnerConfig): Runner;
95
+ /** Build and list a Claude-engine runner without starting it, so watchers can
96
+ * subscribe first. Call `start()` once they have. */
97
+ prepare(config: SessionRunnerConfig): Runner;
98
+ /** Register an already-built runner (a non-Claude engine) and start it. */
99
+ adopt(runner: Runner): Runner;
100
+ /** List a runner without starting it — for a rehydrated session, whose watchers
101
+ * must be subscribed before it comes back up. */
102
+ register(runner: Runner): Runner;
103
+ get(id: string): Runner | undefined;
104
+ list(): SessionInfo[];
105
+ remove(id: string): boolean;
106
+ /** Drop a runner WITHOUT closing it: the session isn't ending, it parked and
107
+ * lives on in its snapshot. Closing here would tell every client it was over. */
108
+ evict(id: string): boolean;
109
+ closeAll(): void;
110
110
  }
111
111
  //#endregion
112
- //#region src/session-store.d.ts
112
+ //#region src/services/session-store.d.ts
113
113
  /**
114
114
  * A session with its live runner torn down, waiting on deferred executions.
115
115
  *
@@ -228,7 +228,7 @@ type FileSessionStoreOptions = {
228
228
  */
229
229
  declare function createFileSessionStore(options?: FileSessionStoreOptions): SessionStore;
230
230
  //#endregion
231
- //#region src/parking.d.ts
231
+ //#region src/services/parking.d.ts
232
232
  type SessionParkOptions = {
233
233
  registry: SessionRegistry;
234
234
  store: SessionStore;
@@ -290,6 +290,18 @@ declare class SessionParkManager {
290
290
  /** Record the config a session was created with. Only sessions the host
291
291
  * remembers can be parked — there is no way to rebuild the others. */
292
292
  remember(sessionId: string, config: SessionRunnerConfig): void;
293
+ /**
294
+ * Re-save a live session's dormant record because something outside the event
295
+ * stream changed it.
296
+ *
297
+ * `#rememberDormant` is otherwise driven by `status_changed` and `system_init`
298
+ * alone, and a rename (`PATCH /sessions/:id`) fires neither — so without this
299
+ * a renamed session that is never touched again keeps its old title on disk
300
+ * and comes back under it. Safe to call for anything: every gate in
301
+ * `#rememberDormant` still applies, so a session that cannot be resumed, has
302
+ * no engine session yet, or is no longer the registry's writes nothing.
303
+ */
304
+ touch(runner: Runner): void;
293
305
  /**
294
306
  * Adopt the store's contents (a durable store after a restart): re-index the
295
307
  * executions and re-arm their watchdogs, no deadline sooner than the grace
@@ -335,7 +347,7 @@ declare class SessionParkManager {
335
347
  close(): void;
336
348
  }
337
349
  //#endregion
338
- //#region src/profile-store.d.ts
350
+ //#region src/services/profile-store.d.ts
339
351
  /**
340
352
  * Where dashboard-managed profiles live. The seam exists for the same reason
341
353
  * `QueueAdapter` does: a single-host deployment wants the bundled file store and
@@ -367,7 +379,7 @@ declare function createMemoryProfileStore(seed?: ProfileInfo[]): ProfileStore;
367
379
  */
368
380
  declare function createFileProfileStore(path?: string): ProfileStore;
369
381
  //#endregion
370
- //#region src/server.d.ts
382
+ //#region src/options.d.ts
371
383
  type SdkSessionLister = (options: {
372
384
  dir?: string;
373
385
  limit?: number;
@@ -753,9 +765,11 @@ type WorkerServer = {
753
765
  }>;
754
766
  close: () => Promise<void>;
755
767
  };
768
+ //#endregion
769
+ //#region src/server.d.ts
756
770
  declare function createWorkerServer(options?: WorkerServerOptions): WorkerServer;
757
771
  //#endregion
758
- //#region src/sandboxed-profile.d.ts
772
+ //#region src/lib/sandboxed-profile.d.ts
759
773
  /**
760
774
  * A `provider` profile that grants a session nothing but the sandbox: the
761
775
  * QuickJS guest, the in-memory VFS, and the model.
@@ -812,7 +826,7 @@ declare function sandboxedProviderProfile(name: string, provider: ProviderConfig
812
826
  mcpServers?: string[];
813
827
  }): ProfileInfo;
814
828
  //#endregion
815
- //#region src/provider-runner.d.ts
829
+ //#region src/lib/provider-runner.d.ts
816
830
  type ProviderRunnerOptions = {
817
831
  /**
818
832
  * The model to run. A function is called per turn with the session's
@@ -882,7 +896,7 @@ type ProviderRunnerOptions = {
882
896
  */
883
897
  declare function createProviderRunner(ctx: EngineRunnerContext, options: ProviderRunnerOptions): Promise<Runner>;
884
898
  //#endregion
885
- //#region src/attachments.d.ts
899
+ //#region src/services/attachments.d.ts
886
900
  type AttachmentStoreOptions = {
887
901
  /** Largest single upload. Default 10 MiB. */maxFileBytes?: number; /** Ceiling on everything one session is holding. Default 64 MiB. */
888
902
  maxSessionBytes?: number;
@@ -946,7 +960,7 @@ declare class AttachmentStore {
946
960
  drop(sessionId: string): void;
947
961
  }
948
962
  //#endregion
949
- //#region src/produced-files.d.ts
963
+ //#region src/services/produced-files.d.ts
950
964
  /** One host file an engine reported writing, as the store holds it. */
951
965
  type ProducedFile = {
952
966
  fileId: string; /** Absolute host path, exactly as the runner reported it. */
@@ -996,5 +1010,54 @@ declare class ProducedFileStore {
996
1010
  drop(sessionId: string): void;
997
1011
  }
998
1012
  //#endregion
999
- export { AttachmentStore, type AttachmentStoreOptions, type Authenticator, BridgeHub, type BridgeHubOptions, type EngineRunnerContext, type FileSessionStoreOptions, MemorySessionStore, type ParkedSessionRecord, type ProducedFile, ProducedFileStore, type ProfileStore, type ProviderRunnerOptions, type QueueServerOptions, type SdkSessionLister, type SessionNotificationOptions, SessionNotifier, SessionParkManager, type SessionParkOptions, SessionRegistry, type SessionRegistryOptions, type SessionStore, type WorkerServer, type WorkerServerOptions, createFileProfileStore, createFileSessionStore, createMemoryProfileStore, createProviderRunner, createWorkerServer, sandboxedProviderProfile, toDurableRecord };
1013
+ //#region src/services/profile-usage.d.ts
1014
+ /**
1015
+ * The gateway's single plan-usage state per profile, fed from every session's
1016
+ * `rate_limit` events and served on `GET /profiles` (`ProfileInfo.usage`).
1017
+ *
1018
+ * Why this exists at all: usage had only ever lived in session transcripts, so
1019
+ * a client attaching to a session that idled since yesterday replayed
1020
+ * yesterday's reading as if current — and a session opened today knew nothing
1021
+ * of what a sibling session on the same account spent an hour ago. The profile
1022
+ * is the account boundary (one config dir / codex home / provider key = one
1023
+ * plan), so the newest reading across all of a profile's sessions is the one
1024
+ * usage state that is ever worth showing. No history: last-write-wins per
1025
+ * window, exactly the reducer's rule on the client side.
1026
+ *
1027
+ * Last-write-wins goes by the **event's own clock**, not arrival order:
1028
+ * `watch()` subscribes from seq 0 (a replayed log is how a rebuilt session's
1029
+ * readings arrive at all), and a replayed yesterday-reading must not clobber
1030
+ * the fresher one another session on the same profile reported live. All
1031
+ * events are stamped by this gateway's clock at emit time, so the comparison
1032
+ * is sound across sessions.
1033
+ *
1034
+ * In-memory on purpose, like the learned default models and the availability
1035
+ * cache: display-only state may start empty after a restart (absent = unknown,
1036
+ * never 0%), and the first session to report refills it.
1037
+ */
1038
+ declare class ProfileUsageTracker {
1039
+ #private;
1040
+ /** Follow a runner's `rate_limit` events for its lifetime. Sessions without a
1041
+ * profile have no account to attribute usage to and are skipped. */
1042
+ watch(runner: Runner): void;
1043
+ /**
1044
+ * The profile's windows as they should be served *now*. Undefined until any
1045
+ * session on the profile has reported (unknown, never 0%).
1046
+ *
1047
+ * The 0%-after-reset inference lives here — at serve time — and nowhere
1048
+ * else, because it is a function of the wall clock: a window whose own
1049
+ * `resetsAt` has passed with no newer reading has provably rolled, so the
1050
+ * pre-reset utilization is no longer merely stale but *wrong*. It cannot be
1051
+ * a producer's job (the producers only relay what the engine said, and the
1052
+ * whole problem is the engine's silence; a fabricated 0% event would be
1053
+ * replayed from transcripts forever as if reported) and must not be every
1054
+ * renderer's (N clients would each reimplement the clock math). The held
1055
+ * reading stays untouched, so a late fresh report still lands by ts, and the
1056
+ * served zero is labeled `inferredReset` — it is a floor, not a report: the
1057
+ * account may have been used outside this gateway since the reset.
1058
+ */
1059
+ usage(profile: string, now?: number): ProfileUsage | undefined;
1060
+ }
1061
+ //#endregion
1062
+ export { AttachmentStore, type AttachmentStoreOptions, type Authenticator, BridgeHub, type BridgeHubOptions, type EngineRunnerContext, type FileSessionStoreOptions, MemorySessionStore, type ParkedSessionRecord, type ProducedFile, ProducedFileStore, type ProfileStore, ProfileUsageTracker, type ProviderRunnerOptions, type QueueServerOptions, type SdkSessionLister, type SessionNotificationOptions, SessionNotifier, SessionParkManager, type SessionParkOptions, SessionRegistry, type SessionRegistryOptions, type SessionStore, type WorkerServer, type WorkerServerOptions, createFileProfileStore, createFileSessionStore, createMemoryProfileStore, createProviderRunner, createWorkerServer, sandboxedProviderProfile, toDurableRecord };
1000
1063
  //# sourceMappingURL=index.d.mts.map