dsh-realtime 0.2.1 → 0.2.3

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Travis Driessen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -22,13 +22,14 @@ export function apply(ctx: Context, config: Config) {
22
22
  }
23
23
  ```
24
24
 
25
- The seam is deliberately thin. It owns three things:
25
+ The seam is deliberately thin. It owns four things:
26
26
 
27
27
  | Owned here | Owned by the adapter |
28
28
  |---|---|
29
29
  | Route registration, all-or-nothing, disposed with the fiber | The transport (WebSocket, WebRTC, in-process) |
30
30
  | Provider metadata and advisory model catalogues | Wire encoding and decoding |
31
31
  | Append bounds (`MAX_APPEND_CHARS`) and coded failures | Token accounting and provider error mapping |
32
+ | The journal, and the settings registry a running plugin can be steered by | Which of its own fields are live — and what a change means |
32
33
 
33
34
  ## What the seam deliberately does not have
34
35
 
@@ -48,6 +49,35 @@ Failures that prevent a session opening are **thrown** from `session()`. Failure
48
49
  opened are delivered to `handlers.onError` — a session that dies mid-conversation must not look like
49
50
  a rejected request. Codes are stable and branchable; message text is not part of the API.
50
51
 
52
+ ## Settings: what a running plugin can be re-steered by
53
+
54
+ `docs/control-plane-fields.md` is the design gate: every field is **live** (read at the moment of use),
55
+ **session-bound** (carried in the provider's `session.start`, so only a new session can change it) or
56
+ **restart-bound** (claimed once at load). `ctx.realtime.settings` is that classification in code —
57
+ `packages/realtime/src/settings.ts` — so a change to a field the protocol cannot honour is *refused with
58
+ the reason* rather than accepted and ignored.
59
+
60
+ ```ts
61
+ ctx.effect(function* () {
62
+ const release = ctx.realtime.settings.register(name, [
63
+ {
64
+ field: 'sessionId',
65
+ kind: 'string',
66
+ scope: 'live',
67
+ get: () => live.sessionId, // read at the moment of use — never a copy
68
+ set: (value: string) => { live.sessionId = value },
69
+ },
70
+ ])
71
+ yield () => { release() }
72
+ }, 'my-plugin.settings')
73
+ ```
74
+
75
+ A key is `<owner>.<field>`. `apply(key, text)` parses by the declared kind, refuses anything the field's
76
+ class cannot honour (`UNKNOWN_SETTING`, `FROZEN_SETTING`, `INVALID_SETTING`) with a reason written to be
77
+ relayed verbatim, journals a successful change as `config.changed` **by key and not by value**, and
78
+ reports the value the plugin now holds. A field declared `secret` is write-only: the surface never
79
+ reports its value back.
80
+
51
81
  ## Registration and disposal
52
82
 
53
83
  `registerAdapter` validates the whole candidate set before mutating anything, so a rejected
package/lib/error.d.ts CHANGED
@@ -26,6 +26,10 @@ export declare const REALTIME_ERROR_CODES: Readonly<{
26
26
  PROVIDER_ERROR: "PROVIDER_ERROR";
27
27
  /** A recorded session could not be read as a recording. */
28
28
  INVALID_RECORDING: "INVALID_RECORDING";
29
+ /** A setting's declaration is malformed: a bad field name, kind, scope, or a kind that does not match what it returns. */
30
+ INVALID_SETTING: "INVALID_SETTING";
31
+ /** A setting is already registered under that key by another registration. */
32
+ DUPLICATE_SETTING: "DUPLICATE_SETTING";
29
33
  /**
30
34
  * The capability is not configured yet — an expected state on a fresh install, not a fault.
31
35
  *
@@ -1 +1 @@
1
- {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,gDAAgD;AAChD,eAAO,MAAM,oBAAoB;IAC/B,iEAAiE;;IAEjE,yEAAyE;;IAEzE,yEAAyE;;IAEzE,wDAAwD;;IAExD,mEAAmE;;IAEnE,2CAA2C;;IAE3C,iGAAiG;;IAEjG,iGAAiG;;IAEjG,2DAA2D;;IAS3D;;;;;OAKG;;IAEH,6FAA6F;;IAE7F,oGAAoG;;IAEpG,6FAA6F;;IAE7F,uEAAuE;;IAEvE,4EAA4E;;IAE5E,+EAA+E;;EAE/E,CAAA;AAEF,2CAA2C;AAC3C,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,OAAO,oBAAoB,CAAC,CAAA;AAEhG;;;;;;;;;GASG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,8FAA8F;IAC9F,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,qFAAqF;IACrF,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AA4BD;;;;;GAKG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACtC,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAA;IAEhC,yEAAyE;IACzE,QAAQ,CAAC,MAAM,EAAE,qBAAqB,GAAG,SAAS,CAAA;IAElD;;;;OAIG;IACH,YAAY,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG;QAAE,MAAM,CAAC,EAAE,qBAAqB,CAAA;KAAE,EAchH;CACF"}
1
+ {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,gDAAgD;AAChD,eAAO,MAAM,oBAAoB;IAC/B,iEAAiE;;IAEjE,yEAAyE;;IAEzE,yEAAyE;;IAEzE,wDAAwD;;IAExD,mEAAmE;;IAEnE,2CAA2C;;IAE3C,iGAAiG;;IAEjG,iGAAiG;;IAEjG,2DAA2D;;IAE3D,0HAA0H;;IAE1H,8EAA8E;;IAS9E;;;;;OAKG;;IAEH,6FAA6F;;IAE7F,oGAAoG;;IAEpG,6FAA6F;;IAE7F,uEAAuE;;IAEvE,4EAA4E;;IAE5E,+EAA+E;;EAE/E,CAAA;AAEF,2CAA2C;AAC3C,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,OAAO,oBAAoB,CAAC,CAAA;AAEhG;;;;;;;;;GASG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,8FAA8F;IAC9F,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,qFAAqF;IACrF,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AA4BD;;;;;GAKG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACtC,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAA;IAEhC,yEAAyE;IACzE,QAAQ,CAAC,MAAM,EAAE,qBAAqB,GAAG,SAAS,CAAA;IAElD;;;;OAIG;IACH,YAAY,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG;QAAE,MAAM,CAAC,EAAE,qBAAqB,CAAA;KAAE,EAchH;CACF"}
package/lib/error.js CHANGED
@@ -26,6 +26,10 @@ export const REALTIME_ERROR_CODES = Object.freeze({
26
26
  PROVIDER_ERROR: 'PROVIDER_ERROR',
27
27
  /** A recorded session could not be read as a recording. */
28
28
  INVALID_RECORDING: 'INVALID_RECORDING',
29
+ /** A setting's declaration is malformed: a bad field name, kind, scope, or a kind that does not match what it returns. */
30
+ INVALID_SETTING: 'INVALID_SETTING',
31
+ /** A setting is already registered under that key by another registration. */
32
+ DUPLICATE_SETTING: 'DUPLICATE_SETTING',
29
33
  // ---------------------------------------------------------------------------------------------
30
34
  // Failure taxonomy. These exist so a consumer can branch on the *class* of a failure rather than
31
35
  // parse prose: a setup state, a rejected credential, an account that cannot pay, and a throttle
package/lib/error.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"error.js","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"error.js","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"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"}
package/lib/index.d.ts CHANGED
@@ -9,10 +9,14 @@
9
9
  * @module dsh-realtime
10
10
  */
11
11
  import { Service, type Context } from '@deepseek-ai/cordis';
12
+ import { Journal } from './journal.ts';
13
+ import { RealtimeSettings } from './settings.ts';
12
14
  import type { RealtimeDelegation, RealtimeModelInfo, RealtimeProviderInfo, RealtimeSession, RealtimeSessionHandlers, RealtimeSessionOptions } from './types.ts';
13
15
  export * from './types.ts';
14
16
  export * from './error.ts';
15
17
  export * from './redact.ts';
18
+ export * from './journal.ts';
19
+ export * from './settings.ts';
16
20
  export { RealtimeError, REALTIME_ERROR_CODES } from './error.ts';
17
21
  declare module '@deepseek-ai/cordis' {
18
22
  interface Context {
@@ -82,6 +86,25 @@ export declare abstract class RealtimeAdapter {
82
86
  */
83
87
  export declare class RealtimeRuntime extends Service {
84
88
  private readonly adapters;
89
+ /**
90
+ * The journal every plugin in this bundle writes to, and the diagnostics route serves.
91
+ *
92
+ * Owned here because this is the only object all of them already hold: the responder knows the
93
+ * delegation, the audio route knows the socket, and the seam is where those two meet. One journal
94
+ * per process — a reader should not be left correlating three partial ones.
95
+ */
96
+ readonly journal: Journal;
97
+ /**
98
+ * The settings every plugin in this bundle declares, and the surface a control plane changes them
99
+ * through.
100
+ *
101
+ * Owned here beside the journal, for the same reason: it is the one object all of them already hold,
102
+ * and a surface split across three of them would leave a reader correlating three partial answers to
103
+ * one question. A setting's class comes from `docs/control-plane-fields.md`, and the registry is what
104
+ * makes that classification bite — a change to a field the protocol cannot honour is refused with the
105
+ * reason, on the same channel it arrived on.
106
+ */
107
+ readonly settings: RealtimeSettings;
85
108
  /**
86
109
  * @param ctx - the Cordis context this service is mounted on.
87
110
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAE3D,OAAO,KAAK,EACV,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,EACf,uBAAuB,EACvB,sBAAsB,EACvB,MAAM,YAAY,CAAA;AAEnB,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAEhE,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,OAAO;QACf,QAAQ,EAAE,eAAe,CAAA;KAC1B;CACF;AAED;;;GAGG;AACH,MAAM,WAAW,yBAAyB;IACxC,6DAA6D;IAC7D,IAAI,IAAI,CAAA;IACR;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;CACnC;AAED;;;;;;GAMG;AACH,8BAAsB,eAAe;IACnC;;;;OAIG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,oBAAoB,CAEnD;IAED;;;;;;;OAOG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,iBAAiB,EAAE,CAAC,CAEnE;IAED;;;;;;;OAOG;IACH,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;CAC5E;AAQD;;;;;GAKG;AACH,qBAAa,eAAgB,SAAQ,OAAO;IAC1C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyC;IAElE;;OAEG;IACH,YAAY,GAAG,EAAE,OAAO,EAEvB;IAED;;;;;;;;OAQG;IACH,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,eAAe,GAAG,yBAAyB,CAiCxF;IAED;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,OAAO;IAgCf;;;;;OAKG;IACH,OAAO,CAAC,MAAM;IASd;;;OAGG;IACH,aAAa,IAAI,oBAAoB,EAAE,CAEtC;IAED;;;;;OAKG;IACH,OAAO,CAAC,YAAY;IAQpB;;;;OAIG;IACG,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAe/D;IAED;;;;;;;;OAQG;IACG,OAAO,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,eAAe,CAAC,CAgBvE;IAED;;;;;;;;;;OAUG;IACH,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAWjE;CACF;AAED,qFAAqF;AACrF,YAAY,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,CAAA;eAE5C,eAAe"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAE3D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,KAAK,EACV,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,EACf,uBAAuB,EACvB,sBAAsB,EACvB,MAAM,YAAY,CAAA;AAEnB,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,eAAe,CAAA;AAC7B,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAEhE,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,OAAO;QACf,QAAQ,EAAE,eAAe,CAAA;KAC1B;CACF;AAED;;;GAGG;AACH,MAAM,WAAW,yBAAyB;IACxC,6DAA6D;IAC7D,IAAI,IAAI,CAAA;IACR;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;CACnC;AAED;;;;;;GAMG;AACH,8BAAsB,eAAe;IACnC;;;;OAIG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,oBAAoB,CAEnD;IAED;;;;;;;OAOG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,iBAAiB,EAAE,CAAC,CAEnE;IAED;;;;;;;OAOG;IACH,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;CAC5E;AAQD;;;;;GAKG;AACH,qBAAa,eAAgB,SAAQ,OAAO;IAC1C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyC;IAElE;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,UAAgB;IAEhC;;;;;;;;;OASG;IACH,QAAQ,CAAC,QAAQ,mBAAqC;IAEtD;;OAEG;IACH,YAAY,GAAG,EAAE,OAAO,EAEvB;IAED;;;;;;;;OAQG;IACH,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,eAAe,GAAG,yBAAyB,CAiCxF;IAED;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,OAAO;IAgCf;;;;;OAKG;IACH,OAAO,CAAC,MAAM;IASd;;;OAGG;IACH,aAAa,IAAI,oBAAoB,EAAE,CAEtC;IAED;;;;;OAKG;IACH,OAAO,CAAC,YAAY;IAQpB;;;;OAIG;IACG,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAe/D;IAED;;;;;;;;OAQG;IACG,OAAO,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,eAAe,CAAC,CAgBvE;IAED;;;;;;;;;;OAUG;IACH,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAWjE;CACF;AAED,qFAAqF;AACrF,YAAY,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,CAAA;eAE5C,eAAe"}
package/lib/index.js CHANGED
@@ -10,9 +10,13 @@
10
10
  */
11
11
  import { Service } from '@deepseek-ai/cordis';
12
12
  import { REALTIME_ERROR_CODES, RealtimeError } from './error.js';
13
+ import { Journal } from './journal.js';
14
+ import { RealtimeSettings } from './settings.js';
13
15
  export * from './types.js';
14
16
  export * from './error.js';
15
17
  export * from './redact.js';
18
+ export * from './journal.js';
19
+ export * from './settings.js';
16
20
  export { RealtimeError, REALTIME_ERROR_CODES } from './error.js';
17
21
  /**
18
22
  * Provider-wire adapter for the realtime session vocabulary.
@@ -50,6 +54,25 @@ export class RealtimeAdapter {
50
54
  */
51
55
  export class RealtimeRuntime extends Service {
52
56
  adapters = new Map();
57
+ /**
58
+ * The journal every plugin in this bundle writes to, and the diagnostics route serves.
59
+ *
60
+ * Owned here because this is the only object all of them already hold: the responder knows the
61
+ * delegation, the audio route knows the socket, and the seam is where those two meet. One journal
62
+ * per process — a reader should not be left correlating three partial ones.
63
+ */
64
+ journal = new Journal();
65
+ /**
66
+ * The settings every plugin in this bundle declares, and the surface a control plane changes them
67
+ * through.
68
+ *
69
+ * Owned here beside the journal, for the same reason: it is the one object all of them already hold,
70
+ * and a surface split across three of them would leave a reader correlating three partial answers to
71
+ * one question. A setting's class comes from `docs/control-plane-fields.md`, and the registry is what
72
+ * makes that classification bite — a change to a field the protocol cannot honour is refused with the
73
+ * reason, on the same channel it arrived on.
74
+ */
75
+ settings = new RealtimeSettings(this.journal);
53
76
  /**
54
77
  * @param ctx - the Cordis context this service is mounted on.
55
78
  */
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,147 @@
1
+ /**
2
+ * The journal: a bounded, redaction-safe record of what the plugin did.
3
+ *
4
+ * S1 story 2, and the substrate for the rest of the sprint — the diagnostics route serves it, the
5
+ * spoken failures narrate from it, and the fault-injection matrix asserts against it. It exists
6
+ * because every failure this project has spent hours on was *unobservable* rather than wrong: the
7
+ * delegation that produced nothing, the append nobody heard, the socket the host refused. A journal
8
+ * turns each of those into a line.
9
+ *
10
+ * Three properties are load-bearing, and each is a test rather than a promise:
11
+ *
12
+ * - **Redaction happens on write, not on read.** A journal that stores the raw text and redacts when
13
+ * serving it has already leaked: the secret is in memory, in a crash dump, and in whatever later
14
+ * edit forgets the second step. Every string is passed through {@link redact} *before* it is
15
+ * retained, so there is no unredacted copy to forget about. (That is design.md invariant 3 —
16
+ * credentials proven safe by a test that fails on a planted string.)
17
+ * - **Bounded, with eviction visible.** The buffer keeps the last `capacity` entries. Every entry
18
+ * carries a monotonic {@link JournalEntry.seq}, so a reader can tell that earlier entries were
19
+ * dropped rather than never recorded — a ring buffer that silently truncates is how "the log is
20
+ * empty" becomes indistinguishable from "nothing happened".
21
+ * - **Ack is not delivery.** Invariant 6: an acknowledgement proves injection, not that anyone heard
22
+ * it. `append.acknowledged` and `speech.played` are separate kinds with separate entries, and
23
+ * nothing here merges them into one "sent" line.
24
+ *
25
+ * @module dsh-realtime/journal
26
+ */
27
+ /** Entries retained when a caller does not say otherwise. */
28
+ export declare const DEFAULT_JOURNAL_CAPACITY = 200;
29
+ /**
30
+ * What a journal entry can describe.
31
+ *
32
+ * The list is deliberately small and closed: an entry kind is a contract with whatever reads the
33
+ * journal later, so adding one is a considered act rather than a free-form log line.
34
+ */
35
+ export type JournalKind =
36
+ /** A voice session opened, or was asked to and could not. */
37
+ 'session.opened' | 'session.closed' | 'session.failed'
38
+ /**
39
+ * The audio route accepted a socket, refused one and said why, or watched one leave.
40
+ *
41
+ * A close is recorded rather than left to be inferred from the absence of later entries: a reader
42
+ * looking at a journal that simply stops cannot tell a client that hung up from a process that died,
43
+ * and that difference is the whole reason anybody opens the journal.
44
+ */
45
+ | 'socket.accepted' | 'socket.rejected' | 'socket.closed'
46
+ /** The model raised a delegation, and the id it will be correlated by. */
47
+ | 'delegation.seen'
48
+ /** A delegated turn was admitted to the session, refused, declined, or ran out of window. */
49
+ | 'prompt.admitted' | 'prompt.refused' | 'prompt.declined' | 'window.elapsed'
50
+ /** A turn produced an answer. */
51
+ | 'answer.received'
52
+ /** A context append was acknowledged on the wire. Not delivery — see invariant 6. */
53
+ | 'append.acknowledged'
54
+ /** Audio was handed to the transport. **Not** a claim that anyone heard it. */
55
+ | 'speech.sent'
56
+ /** The configuration as resolved, so a journal can be read without the profile beside it. */
57
+ | 'config.resolved'
58
+ /**
59
+ * A live setting changed while the plugin was running.
60
+ *
61
+ * Recorded with the setting's **key and not its value**: the value of a secret-bearing setting is
62
+ * exactly the text that must not be retained, and this is the one record built to be read, quoted
63
+ * and pasted. What a reader needs is that a change happened and which setting it was — the value is
64
+ * whatever the plugin now reports through the settings surface.
65
+ */
66
+ | 'config.changed';
67
+ /** One retained entry. */
68
+ export interface JournalEntry {
69
+ /**
70
+ * Monotonic sequence number, never reused and never reset within one journal instance.
71
+ *
72
+ * A gap between the oldest retained `seq` and the newest means entries were evicted, which is the
73
+ * difference between "nothing happened" and "the buffer rolled over".
74
+ */
75
+ readonly seq: number;
76
+ /** Milliseconds since the epoch, as the injecting caller saw it. */
77
+ readonly at: number;
78
+ /** What happened. */
79
+ readonly kind: JournalKind;
80
+ /** Redacted detail fields; keys are the caller's, values are already safe to serve. */
81
+ readonly detail: Readonly<Record<string, string>>;
82
+ }
83
+ /** How a journal is constructed. */
84
+ export interface JournalOptions {
85
+ /** Entries retained before the oldest is evicted. */
86
+ capacity?: number;
87
+ /**
88
+ * Values that must never appear in an entry, however they are spelled.
89
+ *
90
+ * The route's capability token is 32 random bytes of base64url: it has no prefix and no structure,
91
+ * so no pattern can catch it and only a caller holding it can name it. The provider key is
92
+ * normally caught by shape, but pass it here too — a seam that relies on shape alone fails the
93
+ * moment a vendor changes its prefix.
94
+ */
95
+ secrets?: readonly string[];
96
+ }
97
+ /**
98
+ * A bounded, redaction-safe journal of plugin activity.
99
+ *
100
+ * Not a service: it is a plain object so it can be constructed in a test, handed to a route, and
101
+ * read without a Cordis context. The seam owns one instance and lends it to the plugins that write
102
+ * to it.
103
+ */
104
+ export declare class Journal {
105
+ private readonly capacity;
106
+ private readonly secrets;
107
+ private readonly entries;
108
+ private nextSeq;
109
+ /**
110
+ * @param options - capacity and the values that must never be retained.
111
+ * @throws RangeError when `capacity` is not a positive integer — a journal that retains nothing
112
+ * is a failure that looks like silence, which is the defect this module exists to remove.
113
+ */
114
+ constructor(options?: JournalOptions);
115
+ /**
116
+ * Add values that must never be retained, from a plugin that has only just learned them.
117
+ *
118
+ * Additive rather than a constructor argument because secrets arrive with the plugins that hold
119
+ * them, and plugins load in no guaranteed order: the route's capability token does not exist until
120
+ * the plugin that mints it applies, and a provider key arrives with whichever plugin reads the
121
+ * environment. A journal that could only be seeded at construction would have to be replaced to
122
+ * learn either — which is how a sink ends up with two instances and a reader with half a story.
123
+ * @param values - secrets to add; empty and duplicate values are ignored.
124
+ */
125
+ addSecrets(values: readonly string[]): void;
126
+ /**
127
+ * Redact and retain one entry, evicting the oldest when the buffer is full.
128
+ * @param kind - what happened.
129
+ * @param detail - string fields to retain; every value is redacted before it is stored.
130
+ * @param at - epoch milliseconds; defaults to now, and is injectable so a test can pin a time.
131
+ * @returns the entry exactly as it was retained, so a caller can correlate on `seq`.
132
+ */
133
+ record(kind: JournalKind, detail?: Readonly<Record<string, string>>, at?: number): JournalEntry;
134
+ /**
135
+ * Every retained entry, oldest first.
136
+ *
137
+ * Detached: mutating the result cannot reach the journal, so a route serving this cannot be used
138
+ * to tamper with the record it is reporting.
139
+ * @returns a detached, chronologically ordered copy.
140
+ */
141
+ snapshot(): JournalEntry[];
142
+ /** Entries currently retained. */
143
+ get size(): number;
144
+ /** Sequence number of the oldest retained entry, or `undefined` when empty. */
145
+ get oldestSeq(): number | undefined;
146
+ }
147
+ //# sourceMappingURL=journal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"journal.d.ts","sourceRoot":"","sources":["../src/journal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAIH,6DAA6D;AAC7D,eAAO,MAAM,wBAAwB,MAAM,CAAA;AAE3C;;;;;GAKG;AACH,MAAM,MAAM,WAAW;AACrB,6DAA6D;AAC3D,gBAAgB,GAAG,gBAAgB,GAAG,gBAAgB;AACxD;;;;;;GAMG;GACD,iBAAiB,GAAG,iBAAiB,GAAG,eAAe;AACzD,0EAA0E;GACxE,iBAAiB;AACnB,6FAA6F;GAC3F,iBAAiB,GAAG,gBAAgB,GAAG,iBAAiB,GAAG,gBAAgB;AAC7E,iCAAiC;GAC/B,iBAAiB;AACnB,qFAAqF;GACnF,qBAAqB;AACvB,+EAA+E;GAC7E,aAAa;AACf,6FAA6F;GAC3F,iBAAiB;AACnB;;;;;;;GAOG;GACD,gBAAgB,CAAA;AAEpB,0BAA0B;AAC1B,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,qBAAqB;IACrB,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;IAC1B,uFAAuF;IACvF,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CAClD;AAED,oCAAoC;AACpC,MAAM,WAAW,cAAc;IAC7B,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC5B;AAED;;;;;;GAMG;AACH,qBAAa,OAAO;IAClB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,OAAO,CAAI;IAEnB;;;;OAIG;IACH,YAAY,OAAO,GAAE,cAAmB,EAOvC;IAED;;;;;;;;;OASG;IACH,UAAU,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAK1C;IAED;;;;;;OAMG;IACH,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAM,EAAE,EAAE,GAAE,MAAmB,GAAG,YAAY,CAgB9G;IAED;;;;;;OAMG;IACH,QAAQ,IAAI,YAAY,EAAE,CAEzB;IAED,kCAAkC;IAClC,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,+EAA+E;IAC/E,IAAI,SAAS,IAAI,MAAM,GAAG,SAAS,CAElC;CACF"}
package/lib/journal.js ADDED
@@ -0,0 +1,117 @@
1
+ /**
2
+ * The journal: a bounded, redaction-safe record of what the plugin did.
3
+ *
4
+ * S1 story 2, and the substrate for the rest of the sprint — the diagnostics route serves it, the
5
+ * spoken failures narrate from it, and the fault-injection matrix asserts against it. It exists
6
+ * because every failure this project has spent hours on was *unobservable* rather than wrong: the
7
+ * delegation that produced nothing, the append nobody heard, the socket the host refused. A journal
8
+ * turns each of those into a line.
9
+ *
10
+ * Three properties are load-bearing, and each is a test rather than a promise:
11
+ *
12
+ * - **Redaction happens on write, not on read.** A journal that stores the raw text and redacts when
13
+ * serving it has already leaked: the secret is in memory, in a crash dump, and in whatever later
14
+ * edit forgets the second step. Every string is passed through {@link redact} *before* it is
15
+ * retained, so there is no unredacted copy to forget about. (That is design.md invariant 3 —
16
+ * credentials proven safe by a test that fails on a planted string.)
17
+ * - **Bounded, with eviction visible.** The buffer keeps the last `capacity` entries. Every entry
18
+ * carries a monotonic {@link JournalEntry.seq}, so a reader can tell that earlier entries were
19
+ * dropped rather than never recorded — a ring buffer that silently truncates is how "the log is
20
+ * empty" becomes indistinguishable from "nothing happened".
21
+ * - **Ack is not delivery.** Invariant 6: an acknowledgement proves injection, not that anyone heard
22
+ * it. `append.acknowledged` and `speech.played` are separate kinds with separate entries, and
23
+ * nothing here merges them into one "sent" line.
24
+ *
25
+ * @module dsh-realtime/journal
26
+ */
27
+ import { redact } from './redact.js';
28
+ /** Entries retained when a caller does not say otherwise. */
29
+ export const DEFAULT_JOURNAL_CAPACITY = 200;
30
+ /**
31
+ * A bounded, redaction-safe journal of plugin activity.
32
+ *
33
+ * Not a service: it is a plain object so it can be constructed in a test, handed to a route, and
34
+ * read without a Cordis context. The seam owns one instance and lends it to the plugins that write
35
+ * to it.
36
+ */
37
+ export class Journal {
38
+ capacity;
39
+ secrets;
40
+ entries = [];
41
+ nextSeq = 1;
42
+ /**
43
+ * @param options - capacity and the values that must never be retained.
44
+ * @throws RangeError when `capacity` is not a positive integer — a journal that retains nothing
45
+ * is a failure that looks like silence, which is the defect this module exists to remove.
46
+ */
47
+ constructor(options = {}) {
48
+ const capacity = options.capacity ?? DEFAULT_JOURNAL_CAPACITY;
49
+ if (!Number.isInteger(capacity) || capacity < 1) {
50
+ throw new RangeError(`journal capacity must be a positive integer, received ${String(capacity)}`);
51
+ }
52
+ this.capacity = capacity;
53
+ this.secrets = [...options.secrets ?? []];
54
+ }
55
+ /**
56
+ * Add values that must never be retained, from a plugin that has only just learned them.
57
+ *
58
+ * Additive rather than a constructor argument because secrets arrive with the plugins that hold
59
+ * them, and plugins load in no guaranteed order: the route's capability token does not exist until
60
+ * the plugin that mints it applies, and a provider key arrives with whichever plugin reads the
61
+ * environment. A journal that could only be seeded at construction would have to be replaced to
62
+ * learn either — which is how a sink ends up with two instances and a reader with half a story.
63
+ * @param values - secrets to add; empty and duplicate values are ignored.
64
+ */
65
+ addSecrets(values) {
66
+ for (const value of values) {
67
+ if (typeof value !== 'string' || value.length === 0)
68
+ continue;
69
+ if (!this.secrets.includes(value))
70
+ this.secrets.push(value);
71
+ }
72
+ }
73
+ /**
74
+ * Redact and retain one entry, evicting the oldest when the buffer is full.
75
+ * @param kind - what happened.
76
+ * @param detail - string fields to retain; every value is redacted before it is stored.
77
+ * @param at - epoch milliseconds; defaults to now, and is injectable so a test can pin a time.
78
+ * @returns the entry exactly as it was retained, so a caller can correlate on `seq`.
79
+ */
80
+ record(kind, detail = {}, at = Date.now()) {
81
+ const safe = {};
82
+ for (const [key, value] of Object.entries(detail)) {
83
+ safe[key] = redact(value, this.secrets);
84
+ }
85
+ const entry = Object.freeze({
86
+ seq: this.nextSeq++,
87
+ at,
88
+ kind,
89
+ detail: Object.freeze(safe),
90
+ });
91
+ this.entries.push(entry);
92
+ // `shift()` on a bounded array: the buffer is capped, so this stays O(capacity) at worst and
93
+ // the memory ceiling is a property of the type rather than of the caller's discipline.
94
+ while (this.entries.length > this.capacity)
95
+ this.entries.shift();
96
+ return entry;
97
+ }
98
+ /**
99
+ * Every retained entry, oldest first.
100
+ *
101
+ * Detached: mutating the result cannot reach the journal, so a route serving this cannot be used
102
+ * to tamper with the record it is reporting.
103
+ * @returns a detached, chronologically ordered copy.
104
+ */
105
+ snapshot() {
106
+ return this.entries.map(entry => ({ ...entry, detail: { ...entry.detail } }));
107
+ }
108
+ /** Entries currently retained. */
109
+ get size() {
110
+ return this.entries.length;
111
+ }
112
+ /** Sequence number of the oldest retained entry, or `undefined` when empty. */
113
+ get oldestSeq() {
114
+ return this.entries[0]?.seq;
115
+ }
116
+ }
117
+ //# sourceMappingURL=journal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"journal.js","sourceRoot":"","sources":["../src/journal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC,6DAA6D;AAC7D,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAG,CAAA;AAyE3C;;;;;;GAMG;AACH,MAAM,OAAO,OAAO;IACD,QAAQ,CAAQ;IAChB,OAAO,CAAU;IACjB,OAAO,GAAmB,EAAE,CAAA;IACrC,OAAO,GAAG,CAAC,CAAA;IAEnB;;;;OAIG;IACH,YAAY,OAAO,GAAmB,EAAE;QACtC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,wBAAwB,CAAA;QAC7D,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;YAChD,MAAM,IAAI,UAAU,CAAC,yDAAyD,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;QACnG,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAA;QACxB,IAAI,CAAC,OAAO,GAAG,CAAC,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,CAAA;IAC3C,CAAC;IAED;;;;;;;;;OASG;IACH,UAAU,CAAC,MAAyB;QAClC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;gBAAE,SAAQ;YAC7D,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;gBAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAC7D,CAAC;IACH,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAC,IAAiB,EAAE,MAAM,GAAqC,EAAE,EAAE,EAAE,GAAW,IAAI,CAAC,GAAG,EAAE;QAC9F,MAAM,IAAI,GAA2B,EAAE,CAAA;QACvC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAClD,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;QACzC,CAAC;QACD,MAAM,KAAK,GAAiB,MAAM,CAAC,MAAM,CAAC;YACxC,GAAG,EAAE,IAAI,CAAC,OAAO,EAAE;YACnB,EAAE;YACF,IAAI;YACJ,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;SAC5B,CAAC,CAAA;QACF,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACxB,6FAA6F;QAC7F,uFAAuF;QACvF,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,QAAQ;YAAE,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAA;QAChE,OAAO,KAAK,CAAA;IACd,CAAC;IAED;;;;;;OAMG;IACH,QAAQ;QACN,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAA;IAC/E,CAAC;IAED,kCAAkC;IAClC,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAA;IAC5B,CAAC;IAED,+EAA+E;IAC/E,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,CAAA;IAC7B,CAAC;CACF"}