浏览代码

fix(client): satisfy strict observable contracts

imccyu 1 月之前
父节点
当前提交
b8a19413e9

+ 4 - 4
packages/client/ui-chat/src/client/contract/snapshot.ts

@@ -15,17 +15,17 @@ export type {
 /** Per-key observable used by one mounted Chat Node Seat. */
 export interface ChatNodeSource {
   /** @returns the current Node for this source's stable key. */
-  getSnapshot(): ChatConversationViewNode | undefined
+  readonly getSnapshot: () => ChatConversationViewNode | undefined
   /** @param listener - callback for changes to this key. @returns the unsubscribe function. */
-  subscribe(listener: () => void): () => void
+  readonly subscribe: (listener: () => void) => () => void
 }
 
 /** Per-key observable for the Turn-process presentation surrounding one Chat Node. */
 export interface ChatNodeProcessSource {
   /** @returns the current presentation, or absence outside a projected Turn process. */
-  getSnapshot(): ChatTurnProcessPresentation | undefined
+  readonly getSnapshot: () => ChatTurnProcessPresentation | undefined
   /** @param listener - callback for presentation changes. @returns the unsubscribe function. */
-  subscribe(listener: () => void): () => void
+  readonly subscribe: (listener: () => void) => () => void
 }
 
 /** Stable live per-key reader for Chat nodes. */

+ 1 - 1
packages/client/ui-chat/tests/chat-node-source.client.spec.ts

@@ -24,7 +24,7 @@ function userNode(index: number, text = `message ${String(index)}`): ChatConvers
       content: [{ type: 'text', text }],
       source: null,
     },
-  } as ChatConversationViewNode
+  }
 }
 
 describe('Chat Node keyed sources', () => {

+ 19 - 14
packages/client/ui-conversation/src/client/contract/conversation.ts

@@ -16,9 +16,9 @@ export interface ConversationStepDataMap {}
 /** Observable value for one independently owned Location-data key. */
 export interface ConversationLocationDataSource<Value> {
   /** @returns the current value. */
-  getSnapshot(): Value
+  readonly getSnapshot: () => Value
   /** @param listener - callback for value changes. @returns the unsubscribe function. */
-  subscribe(listener: () => void): () => void
+  readonly subscribe: (listener: () => void) => () => void
 }
 
 /** Stable keyed reader for independently owned Location business values. */
@@ -47,30 +47,35 @@ interface ConversationLocationDataValue {
   readonly value: unknown
 }
 
-type RegisteredTurnData = {
-  [Key in keyof ConversationTurnDataMap & string]: {
+type RegisteredTurnData<DataMap extends object> = {
+  [Key in Extract<keyof DataMap, string>]: {
     readonly kind: 'turn'
     readonly turn: number
     readonly key: Key
-    readonly value: ConversationTurnDataMap[Key]
+    readonly value: DataMap[Key]
   }
-}[keyof ConversationTurnDataMap & string]
+}[Extract<keyof DataMap, string>]
 
-type RegisteredStepData = {
-  [Key in keyof ConversationStepDataMap & string]: {
+type RegisteredStepData<DataMap extends object> = {
+  [Key in Extract<keyof DataMap, string>]: {
     readonly kind: 'step'
     readonly turn: number
     readonly step: number
     readonly key: Key
-    readonly value: ConversationStepDataMap[Key]
+    readonly value: DataMap[Key]
   }
-}[keyof ConversationStepDataMap & string]
+}[Extract<keyof DataMap, string>]
 
-/** One Definition-owned value attached to an Engine-owned Turn or Step. */
-export type ConversationLocationData =
-  [keyof ConversationTurnDataMap | keyof ConversationStepDataMap] extends [never]
+type ConversationLocationDataOf<TurnData extends object, StepData extends object> =
+  [keyof TurnData | keyof StepData] extends [never]
     ? ConversationLocationDataValue
-    : RegisteredTurnData | RegisteredStepData
+    : RegisteredTurnData<TurnData> | RegisteredStepData<StepData>
+
+/** One Definition-owned value attached to an Engine-owned Turn or Step. */
+export type ConversationLocationData = ConversationLocationDataOf<
+  ConversationTurnDataMap,
+  ConversationStepDataMap
+>
 
 /** Immutable resolved boundary for one Agent step. */
 export interface StepLocation {