Merge remote-tracking branch 'origin/master' into feat/web-message-feedback-ui

Adapt to two contract changes master introduced:

- The generated Remote face now wraps every business result in
  RemoteResult, folding carrier failures into an ok:false branch instead
  of rejecting. The controller reads that envelope at its three call
  sites and maps a carrier failure onto the same settled shape the
  controls already render; three specs cover the new branch.
- Client packages split their tsconfig into host and client halves, and
  the host aggregate now compiles any test not named *.client.spec.*.
  Rename this package's specs to the client convention and drop the
  ../connection project reference, which pointed at a solution file that
  no longer carries the client sources.

Keep master's mount loop with its rollback-on-failure in api-remotes and
add messageFeedbackRemote to it.
This commit is contained in:
Chinesezjc
2026-08-12 10:43:23 +08:00
parent 47f254a252
commit b462d5fd69
507 changed files with 3130 additions and 2238 deletions

View File

@@ -7,6 +7,7 @@
* @module @deepseek-ai/dsh-client-ui-feedback/client/controller
*/
import type { RemoteResult } from '@deepseek-ai/dsh-type-meta'
import type { HostObservable } from '@deepseek-ai/dsh-client-ui-slots'
import type { MessageId, SessionId } from '@deepseek-ai/dsh-client-connection/client'
import type {
@@ -17,21 +18,26 @@ import type {
MessageFeedbackRating,
} from '@deepseek-ai/dsh-message-feedback/types'
/** The three Remote calls this controller needs, named without the transport. */
/**
* The three Remote calls this controller needs. The generated face wraps every
* business result in {@link RemoteResult}: a carrier failure arrives as the
* `ok: false` branch rather than a rejection, so this controller reads one
* envelope and never wraps a call to recover a transport error.
*/
export interface MessageFeedbackRemote {
list: (request: { sessionId: SessionId }) => Promise<MessageFeedbackListResult>
list: (request: { sessionId: SessionId }) => Promise<RemoteResult<MessageFeedbackListResult>>
put: (request: {
sessionId: SessionId
messageId: MessageId
rating: MessageFeedbackRating
note?: string
ifVersion: MessageFeedbackItem['version'] | null
}) => Promise<MessageFeedbackPutResult>
}) => Promise<RemoteResult<MessageFeedbackPutResult>>
delete: (request: {
sessionId: SessionId
messageId: MessageId
ifVersion: MessageFeedbackItem['version']
}) => Promise<MessageFeedbackDeleteResult>
}) => Promise<RemoteResult<MessageFeedbackDeleteResult>>
}
/** Load state of the one list read that seeds every per-message control. */
@@ -87,6 +93,11 @@ function fail(code: string): FeedbackActionResult {
return { ok: false, error: { code, message: describe(code) } }
}
/** Carrier failure rendered with the Host-supplied code and message. */
function carrierFailure(error: { code: string; message: string }): FeedbackActionResult {
return { ok: false, error: { code: error.code, message: error.message } }
}
/**
* Per-session feedback object layer. One instance backs every per-message
* control in that Session, so a single list read seeds them all.
@@ -231,13 +242,15 @@ export class FeedbackController implements HostObservable<FeedbackView> {
note: string | undefined,
observed: MessageFeedbackItem | undefined,
): Promise<FeedbackActionResult> {
const result = await this.remote.put({
const carried = await this.remote.put({
sessionId: this.sessionId,
messageId,
rating,
...(note === undefined ? {} : { note }),
ifVersion: observed?.version ?? null,
})
if (!carried.ok) return carrierFailure(carried.error)
const result = carried.value
if (result.ok) {
this.commit(messageId, result.value)
return OK
@@ -251,11 +264,13 @@ export class FeedbackController implements HostObservable<FeedbackView> {
messageId: MessageId,
observed: MessageFeedbackItem,
): Promise<FeedbackActionResult> {
const result = await this.remote.delete({
const carried = await this.remote.delete({
sessionId: this.sessionId,
messageId,
ifVersion: observed.version,
})
if (!carried.ok) return carrierFailure(carried.error)
const result = carried.value
if (result.ok) {
this.commit(messageId, null)
return OK
@@ -273,8 +288,13 @@ export class FeedbackController implements HostObservable<FeedbackView> {
/** Fetch the whole sidecar and publish it as the seeded view. */
private async load(): Promise<FeedbackActionResult> {
try {
const result = await this.remote.list({ sessionId: this.sessionId })
const carried = await this.remote.list({ sessionId: this.sessionId })
if (this.disposed) return OK
if (!carried.ok) {
this.publish({ status: 'error', items: this.view.items, error: carried.error.message })
return carrierFailure(carried.error)
}
const result = carried.value
if (!result.ok) {
this.publish({ status: 'error', items: this.view.items, error: describe(result.error.code) })
return fail(result.error.code)