fix(web): unblock remote welcome onboarding
This commit is contained in:
@@ -41,6 +41,18 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
|
||||
/** Dictionary namespace owned by this plugin (shell chrome + General copy). */
|
||||
const NS = 'settings'
|
||||
|
||||
function isLoopbackHostname(hostname: string): boolean {
|
||||
if (hostname === 'localhost' || hostname === '[::1]') return true
|
||||
const parts = hostname.split('.')
|
||||
return parts.length === 4
|
||||
&& parts[0] === '127'
|
||||
&& parts.every(part => /^\d{1,3}$/.test(part) && Number(part) <= 255)
|
||||
}
|
||||
|
||||
function welcomePersistence(): 'host' | 'memory' {
|
||||
return typeof location === 'undefined' || isLoopbackHostname(location.hostname) ? 'host' : 'memory'
|
||||
}
|
||||
|
||||
/**
|
||||
* Required services (cordis fiber inject). The target slots are declared by
|
||||
* ui-settings' apply, whose activation order relative to this one is NOT
|
||||
@@ -61,7 +73,7 @@ export function apply(ctx: ClientContext): void {
|
||||
// locale/change re-registration wiring.
|
||||
const t = ctx.locale.bind(NS)
|
||||
const connection = ctx.get('connection') as ConnectionHandle
|
||||
const welcomeController = new WelcomeNoticeStore(connection.api)
|
||||
const welcomeController = new WelcomeNoticeStore(connection.api, welcomePersistence())
|
||||
const useWelcomeSnapshot = bindSnapshotSelector(welcomeController.store)
|
||||
const welcomeInjected = (): WelcomeNoticeInjected => ({
|
||||
controller: welcomeController,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/** Durable welcome-notice state over the Host settings document. */
|
||||
/** Welcome-notice state, durable when the browser may use Host settings. */
|
||||
|
||||
import type { IApiClient, SettingsNamespaceView } from '@deepseek-ai/dsh-client-connection/client'
|
||||
import type { SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client'
|
||||
@@ -24,7 +24,7 @@ function acknowledgementOf(view: SettingsNamespaceView): string | undefined {
|
||||
return typeof value === 'string' ? value : undefined
|
||||
}
|
||||
|
||||
/** Coordinates welcome acknowledgement reads and the sole durable write. */
|
||||
/** Coordinates durable Host acknowledgement or a process-local remote fallback. */
|
||||
export class WelcomeNoticeStore {
|
||||
/** uSES-safe state source shared by the registered welcome step. */
|
||||
readonly store: SnapshotStore<WelcomeNoticeState> = createSnapshotStore({
|
||||
@@ -33,12 +33,22 @@ export class WelcomeNoticeStore {
|
||||
|
||||
private generation = 0
|
||||
|
||||
/** @param api - settings wire face used for durable reads and writes. */
|
||||
constructor(private readonly api: Pick<IApiClient, 'settings'>) {}
|
||||
/**
|
||||
* @param api - settings wire face used for durable reads and writes.
|
||||
* @param persistence - remote browsers use memory because settings is loopback-only.
|
||||
*/
|
||||
constructor(
|
||||
private readonly api: Pick<IApiClient, 'settings'>,
|
||||
private readonly persistence: 'host' | 'memory' = 'host',
|
||||
) {}
|
||||
|
||||
/** Load the current acknowledgement from the Host settings document. */
|
||||
/** Load the acknowledgement from Host settings or initialize process-local state. */
|
||||
async load(): Promise<void> {
|
||||
const generation = ++this.generation
|
||||
if (this.persistence === 'memory') {
|
||||
this.store.update((state) => { state.status = 'ready'; state.error = null })
|
||||
return
|
||||
}
|
||||
this.store.update((state) => { state.status = 'loading'; state.error = null })
|
||||
try {
|
||||
const response = await this.api.settings.describe({})
|
||||
@@ -64,12 +74,20 @@ export class WelcomeNoticeStore {
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist this copy version. The path mutation is idempotent across tabs and
|
||||
* preserves every sibling setting; failure leaves the step unacknowledged.
|
||||
* @returns true only when the Host committed the acknowledgement.
|
||||
* Acknowledge this copy version. The Host path mutation is idempotent across
|
||||
* tabs and preserves sibling settings; remote fallback changes only this store.
|
||||
* @returns true when the selected persistence mode accepted the acknowledgement.
|
||||
*/
|
||||
async acknowledge(): Promise<boolean> {
|
||||
const generation = ++this.generation
|
||||
if (this.persistence === 'memory') {
|
||||
this.store.update((state) => {
|
||||
state.status = 'ready'
|
||||
state.acknowledged = true
|
||||
state.error = null
|
||||
})
|
||||
return true
|
||||
}
|
||||
this.store.update((state) => { state.status = 'saving'; state.error = null })
|
||||
try {
|
||||
const response = await this.api.settings.mutate({
|
||||
|
||||
Reference in New Issue
Block a user