@deepseek-ai/dsh-client-test-runtime 0.1.5-rc.2 → 0.1.6-alpha.2
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/README.i18n.yaml +2 -2
- package/README.md +39 -4
- package/README.zh.md +47 -12
- package/lib/index.js +467 -258
- package/lib/types/assembly/bundle-roster.d.ts +15 -0
- package/lib/types/assembly/index.d.ts +15 -0
- package/lib/types/assembly/modules.d.ts +25 -0
- package/lib/types/assembly/remote-default-responses.d.ts +12 -0
- package/lib/types/assembly/remote-proxies.d.ts +20 -0
- package/lib/types/assembly/roster.d.ts +80 -0
- package/lib/types/assembly/test-client.d.ts +83 -0
- package/lib/types/assembly/vitest.d.ts +24 -0
- package/lib/types/fixtures.d.ts +2 -0
- package/lib/types/index.d.ts +22 -11
- package/lib/types/remote.d.ts +8 -0
- package/lib/types/sessions.d.ts +52 -38
- package/lib/types/workspaces.d.ts +6 -0
- package/package.json +54 -33
- package/lib/types/settings-remote.d.ts +0 -83
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ClientRoster } from './roster.ts';
|
|
2
|
+
/** The `web` profile's bundle layers, in the order `dsh --profile web` applies them (app-boot `PROFILE_TEMPLATES.web`). */
|
|
3
|
+
export declare const WEB_PROFILE_BUNDLES: readonly string[];
|
|
4
|
+
/**
|
|
5
|
+
* Compose the browser roster of `bundles`, applied in order.
|
|
6
|
+
* @param bundles - bundle package names in application order.
|
|
7
|
+
* @param anchor - file whose package resolution locates the bundles; default this package.
|
|
8
|
+
* @returns the roster in composition order, one row per package.
|
|
9
|
+
* @throws {Error} when a bundle, its patch file, or an enabled row's package does not resolve, when the patch list
|
|
10
|
+
* is not a list or does not apply as written, or when a browser row's `disabled` is a `!!js` expression.
|
|
11
|
+
*/
|
|
12
|
+
export declare function bundleRoster(bundles: readonly string[], anchor?: string): ClientRoster;
|
|
13
|
+
/** The `web` profile's browser roster, composed from its bundles at import. */
|
|
14
|
+
export declare const webApp: ClientRoster;
|
|
15
|
+
//# sourceMappingURL=bundle-roster.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whole-client tier entry (deep import only:
|
|
3
|
+
* `@deepseek-ai/dsh-client-test-runtime/src/assembly/index.ts`). Kept out of
|
|
4
|
+
* the package root so slot-tier specs do not load the assembly machinery.
|
|
5
|
+
* @module @deepseek-ai/dsh-client-test-runtime/src/assembly
|
|
6
|
+
*/
|
|
7
|
+
export { ClientRoster } from './roster.ts';
|
|
8
|
+
export type { AssemblyPlan, ClientPluginModule, ClientRosterRow } from './roster.ts';
|
|
9
|
+
export { TestClient } from './test-client.ts';
|
|
10
|
+
export type { TestClientOptions } from './test-client.ts';
|
|
11
|
+
export { remoteDefaultResponses } from './remote-default-responses.ts';
|
|
12
|
+
export { bundleRoster, webApp } from './bundle-roster.ts';
|
|
13
|
+
export { createClientTest } from './vitest.ts';
|
|
14
|
+
export type { ClientTestFixtures } from './vitest.ts';
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ClientModuleLoader, WebBootGraph } from '@deepseek-ai/dsh-client-modules/client';
|
|
2
|
+
import type { AssemblyPlan, ClientPluginModule } from './roster.ts';
|
|
3
|
+
/** The bootstrap row: always this process's static namespace, never a dynamic import or a `provide` replacement. */
|
|
4
|
+
export declare const MODULES_PACKAGE = "@deepseek-ai/dsh-client-modules";
|
|
5
|
+
/**
|
|
6
|
+
* Resolve each roster row to its plugin module: `plan.provide[name]` when
|
|
7
|
+
* present, otherwise a `/client` import resolved by the repository's tsconfig
|
|
8
|
+
* path aliases under Vitest. The bootstrap row is the
|
|
9
|
+
* statically imported `@deepseek-ai/dsh-client-modules/client` namespace.
|
|
10
|
+
* @param plan - validated plan.
|
|
11
|
+
* @returns package name → module, in roster order.
|
|
12
|
+
* @throws {Error} when an import fails (the package name prefixes the original message) or the bootstrap row is provided.
|
|
13
|
+
*/
|
|
14
|
+
export declare function loadPluginModules(plan: AssemblyPlan): Promise<ReadonlyMap<string, ClientPluginModule>>;
|
|
15
|
+
/**
|
|
16
|
+
* Build the production module system over queued factories returning the
|
|
17
|
+
* loaded namespaces. The bootstrap row uses `bootstrapModule`; `staticModules`
|
|
18
|
+
* is empty because namespaces already hold their own imports. Missing factories
|
|
19
|
+
* reject through `loadBundle` without fetching.
|
|
20
|
+
* @param graph - raw boot graph from `graphFromRoster`; `createClientModuleSystem` parses it.
|
|
21
|
+
* @param modules - loaded plugin modules keyed by package name.
|
|
22
|
+
* @returns module system to install as `loader.internal`; its `manifest` is the parsed graph.
|
|
23
|
+
*/
|
|
24
|
+
export declare function createInProcessModules(graph: WebBootGraph, modules: ReadonlyMap<string, ClientPluginModule>): ClientModuleLoader;
|
|
25
|
+
//# sourceMappingURL=modules.d.ts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default responses for every Remote endpoint the web assembly calls while
|
|
3
|
+
* booting and rendering with no sessions, no workspaces, and default settings.
|
|
4
|
+
* The comment above each row names the plugin that calls it; endpoints boot
|
|
5
|
+
* never touches stay absent so a new call fails loud. `$events` is built into
|
|
6
|
+
* `RemoteMock`.
|
|
7
|
+
* @module @deepseek-ai/dsh-client-test-runtime/src/assembly/remote-default-responses
|
|
8
|
+
*/
|
|
9
|
+
import { type RemoteTable } from '@deepseek-ai/dsh-remote-mock';
|
|
10
|
+
/** Default responses of the boot-time Remote endpoints; a spec loads it first and layers its own table on top. */
|
|
11
|
+
export declare const remoteDefaultResponses: RemoteTable;
|
|
12
|
+
//# sourceMappingURL=remote-default-responses.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { RemoteMock } from '@deepseek-ai/dsh-remote-mock';
|
|
2
|
+
import type { ClientPluginModule } from './roster.ts';
|
|
3
|
+
/** The assembly row the proxies stand in for; its generated clients exist only in built `lib/`. */
|
|
4
|
+
export declare const REMOTES_PACKAGE = "@deepseek-ai/dsh-api-remotes";
|
|
5
|
+
/**
|
|
6
|
+
* Namespaces to provide: every `remote.<ns>` a roster module injects, plus the
|
|
7
|
+
* namespace of every endpoint the mock has a rule for.
|
|
8
|
+
* @param modules - loaded roster modules.
|
|
9
|
+
* @param mock - the spec's mock.
|
|
10
|
+
* @returns sorted namespace names.
|
|
11
|
+
*/
|
|
12
|
+
export declare function remoteNamespacesOf(modules: Iterable<ClientPluginModule>, mock: RemoteMock): readonly string[];
|
|
13
|
+
/**
|
|
14
|
+
* Plugin providing the namespace proxies; `TestClient.start` mounts it before the Loader rows.
|
|
15
|
+
* @param namespaces - namespaces to provide.
|
|
16
|
+
* @param mock - the spec's mock, asked for each endpoint's mode.
|
|
17
|
+
* @returns the plugin.
|
|
18
|
+
*/
|
|
19
|
+
export declare function remoteProxiesPlugin(namespaces: readonly string[], mock: RemoteMock): ClientPluginModule;
|
|
20
|
+
//# sourceMappingURL=remote-proxies.d.ts.map
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client roster: the ordered package-name rows a whole-client test boots, and
|
|
3
|
+
* the plan that annotates one with the rows the test provides itself. `webApp`
|
|
4
|
+
* and `bundleRoster` (`./bundle-roster.ts`) read rosters from the bundle patch
|
|
5
|
+
* files; a spec may also build one inline with {@link ClientRoster.of}.
|
|
6
|
+
* @module @deepseek-ai/dsh-client-test-runtime/src/assembly/roster
|
|
7
|
+
*/
|
|
8
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
9
|
+
import type { WebBootGraph } from '@deepseek-ai/dsh-client-modules/client';
|
|
10
|
+
/** One browser plugin row as `dsh.client` declares it, keyed by package name. */
|
|
11
|
+
export interface ClientRosterRow {
|
|
12
|
+
/** Package name (== manifest entry id == Loader entry name). */
|
|
13
|
+
readonly name: string;
|
|
14
|
+
/** Package-name dependency edges from `dsh.client.inject` ([] when absent). */
|
|
15
|
+
readonly inject: readonly string[];
|
|
16
|
+
/** Stage-one prefetch mark from `dsh.client.immediately` (false when absent). */
|
|
17
|
+
readonly immediately: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Synthesize the raw `WebBootGraph` for `rows`: one `application` batch
|
|
21
|
+
* holding every row, `rev: 'local'`, placeholder `/plugins/<name>/client.js`
|
|
22
|
+
* URLs, since every module is seeded in process and never fetched. Validation
|
|
23
|
+
* stays with the production `parseBootManifest` inside the module system:
|
|
24
|
+
* duplicate names and an empty roster are rejected there, not here.
|
|
25
|
+
* @param rows - roster rows in composition order.
|
|
26
|
+
* @returns the unparsed graph, as `createClientModuleSystem` consumes it.
|
|
27
|
+
*/
|
|
28
|
+
export declare function graphFromRoster(rows: readonly ClientRosterRow[]): WebBootGraph;
|
|
29
|
+
/** Immutable, name-addressable roster. */
|
|
30
|
+
export declare class ClientRoster {
|
|
31
|
+
readonly rows: readonly ClientRosterRow[];
|
|
32
|
+
/**
|
|
33
|
+
* Build a roster from rows; duplicate names throw.
|
|
34
|
+
* @param rows - roster rows in composition order.
|
|
35
|
+
* @returns roster.
|
|
36
|
+
*/
|
|
37
|
+
static of(rows: readonly ClientRosterRow[]): ClientRoster;
|
|
38
|
+
private constructor();
|
|
39
|
+
/**
|
|
40
|
+
* Keep only `names`, preserving roster order; an unknown name throws with the roster listed.
|
|
41
|
+
* @param names - package names to keep.
|
|
42
|
+
* @returns sub-roster.
|
|
43
|
+
*/
|
|
44
|
+
pick(names: readonly string[]): ClientRoster;
|
|
45
|
+
/**
|
|
46
|
+
* The named rows plus every row they inject, transitively, in roster order: the rows a spec needs to boot the
|
|
47
|
+
* named plugins as the bundle composes them. The shell's platform modules (`PLATFORM_MODULES`, seeded statically
|
|
48
|
+
* rather than loaded as rows) end the walk. An unknown name throws with the roster listed; a row injecting any
|
|
49
|
+
* other package outside the roster throws, since the bundle itself would not boot.
|
|
50
|
+
* @param names - package names whose dependency cone to keep.
|
|
51
|
+
* @returns sub-roster.
|
|
52
|
+
*/
|
|
53
|
+
closure(names: readonly string[]): ClientRoster;
|
|
54
|
+
/**
|
|
55
|
+
* Drop `names`; an unknown name throws with the roster listed.
|
|
56
|
+
* @param names - package names to drop.
|
|
57
|
+
* @returns sub-roster.
|
|
58
|
+
*/
|
|
59
|
+
without(names: readonly string[]): ClientRoster;
|
|
60
|
+
private known;
|
|
61
|
+
}
|
|
62
|
+
/** The module face the Loader materializes for one client plugin row. */
|
|
63
|
+
export interface ClientPluginModule {
|
|
64
|
+
apply(ctx: Context, config?: unknown): unknown;
|
|
65
|
+
readonly inject?: readonly string[] | Readonly<Record<string, unknown>>;
|
|
66
|
+
readonly Config?: unknown;
|
|
67
|
+
}
|
|
68
|
+
/** What to boot and what the test supplies itself. */
|
|
69
|
+
export interface AssemblyPlan {
|
|
70
|
+
readonly roster: ClientRoster;
|
|
71
|
+
/** Row replacements by package name (the test's own implementation of that row). Names outside the roster throw. */
|
|
72
|
+
readonly provide?: Readonly<Record<string, ClientPluginModule>>;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Validate a plan against its roster.
|
|
76
|
+
* @param plan - plan to check.
|
|
77
|
+
* @throws {Error} naming any `provide` key outside the roster.
|
|
78
|
+
*/
|
|
79
|
+
export declare function assertPlan(plan: AssemblyPlan): void;
|
|
80
|
+
//# sourceMappingURL=roster.d.ts.map
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whole-client test carrier: boots an {@link AssemblyPlan} through the
|
|
3
|
+
* production `bootClient` over an in-process module table, with a
|
|
4
|
+
* `RemoteMock` bound to that client's Connection plugin instance.
|
|
5
|
+
* @module @deepseek-ai/dsh-client-test-runtime/src/assembly/test-client
|
|
6
|
+
*/
|
|
7
|
+
import { Context } from '@deepseek-ai/cordis';
|
|
8
|
+
import { type ConnectionHandle } from '@deepseek-ai/dsh-client-connection/client';
|
|
9
|
+
import type { RemoteMock } from '@deepseek-ai/dsh-remote-mock';
|
|
10
|
+
import { type AssemblyPlan } from './roster.ts';
|
|
11
|
+
/** Carrier options. */
|
|
12
|
+
export interface TestClientOptions {
|
|
13
|
+
/**
|
|
14
|
+
* Mount `uiRenderer` into an element (a fresh `document.body` child when `true`); requires jsdom and a roster
|
|
15
|
+
* that provides `uiRenderer`. Default false.
|
|
16
|
+
*/
|
|
17
|
+
readonly mount?: boolean | HTMLElement;
|
|
18
|
+
/** Wait for `ctx.connection.state === 'connected'` before returning. Default true. */
|
|
19
|
+
readonly awaitConnected?: boolean;
|
|
20
|
+
/** Readiness budget in milliseconds before `start` rejects with the mock log summary. Default 5000. */
|
|
21
|
+
readonly connectTimeoutMs?: number;
|
|
22
|
+
}
|
|
23
|
+
/** A booted client under test. */
|
|
24
|
+
export declare class TestClient {
|
|
25
|
+
readonly ctx: Context;
|
|
26
|
+
readonly mock: RemoteMock;
|
|
27
|
+
readonly container: HTMLElement | undefined;
|
|
28
|
+
private readonly restore;
|
|
29
|
+
/**
|
|
30
|
+
* Load the roster's modules, bind this client's mock to its Connection row,
|
|
31
|
+
* hold the jsdom shims, and boot through `bootClient` over the synthesized
|
|
32
|
+
* boot graph; afterwards optionally mount and wait for the connection. The
|
|
33
|
+
* bound row replaces only the page-global input adapter: both paths call
|
|
34
|
+
* `installConnection`, while this path supplies the mock carrier, uses
|
|
35
|
+
* default recovery timings, and captures the current page hostname once for
|
|
36
|
+
* later reloads. A caller-provided Connection row remains unchanged and owns
|
|
37
|
+
* its readiness behavior. The `@deepseek-ai/dsh-api-remotes` row is
|
|
38
|
+
* dropped from the roster: its generated Remote clients exist only in built
|
|
39
|
+
* `lib/`, and the `remote.<ns>` services the roster injects (plus the
|
|
40
|
+
* namespaces the mock has rules for at this point) are provided as
|
|
41
|
+
* contract-free proxies over the same Connection instead; a `provide` entry
|
|
42
|
+
* for that row is refused. On any failure the context is disposed, an owned
|
|
43
|
+
* mount removed, and this client's hold on the shims released before the
|
|
44
|
+
* original error is rethrown.
|
|
45
|
+
* @param plan - roster and annotations.
|
|
46
|
+
* @param mock - Remote mock answering every Gateway call.
|
|
47
|
+
* @param options - mount and readiness options.
|
|
48
|
+
* @returns the booted client.
|
|
49
|
+
*/
|
|
50
|
+
static start(plan: AssemblyPlan, mock: RemoteMock, options?: TestClientOptions): Promise<TestClient>;
|
|
51
|
+
private disposing;
|
|
52
|
+
private constructor();
|
|
53
|
+
/** The roster's Connection service (no `Context` augmentation declares it); throws when the roster provides none. */
|
|
54
|
+
get connection(): ConnectionHandle;
|
|
55
|
+
/** Flush pending React work and microtasks inside `act` (plain microtask flush without a DOM). */
|
|
56
|
+
flush(): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Rebuild one Loader entry: Client Modules' registry-first fiber teardown, then
|
|
59
|
+
* `entry.refresh()`. Each client's module table retains its own instance-bound
|
|
60
|
+
* Connection plugin, so reloads do not coordinate through process globals.
|
|
61
|
+
* Requires a live client: after `dispose()` the Loader holds no entries and
|
|
62
|
+
* the lookup throws before teardown.
|
|
63
|
+
* @param name - package name of the row.
|
|
64
|
+
*/
|
|
65
|
+
reload(name: string): Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* Remove one Loader entry and wait for its plugin cleanup.
|
|
68
|
+
* @param name - package name of the row.
|
|
69
|
+
*/
|
|
70
|
+
unload(name: string): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Dispose the plugin tree, then drop an owned mount and release this
|
|
73
|
+
* client's hold on the shared jsdom shims even when the tree fails to dispose,
|
|
74
|
+
* then `mock.assertNoUnmatched()` last so its failure is the test's reason
|
|
75
|
+
* without skipping the cleanup; when both the tree and the check fail, one
|
|
76
|
+
* error carries both messages. The first call owns the teardown and reports
|
|
77
|
+
* its failure; every later call waits for that teardown and resolves.
|
|
78
|
+
*/
|
|
79
|
+
dispose(): Promise<void>;
|
|
80
|
+
private teardown;
|
|
81
|
+
private entryOf;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=test-client.d.ts.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** Test-scoped Remote mock and lazy client boot, owned by native Vitest fixtures. */
|
|
2
|
+
import { type TestAPI } from 'vitest';
|
|
3
|
+
import { RemoteMock, type MockedRemote } from '@deepseek-ai/dsh-remote-mock';
|
|
4
|
+
import type { AssemblyPlan } from './roster.ts';
|
|
5
|
+
import { TestClient, type TestClientOptions } from './test-client.ts';
|
|
6
|
+
/** Per-test controls; configure the mock before awaiting `start()`. */
|
|
7
|
+
export interface ClientTestFixtures {
|
|
8
|
+
/** Fresh mock with the assembly's default responses already loaded. */
|
|
9
|
+
mock: RemoteMock;
|
|
10
|
+
/** Namespace proxy backed by the same native mocks used by the Connection carrier. */
|
|
11
|
+
remote: MockedRemote;
|
|
12
|
+
/** Await the one client owned by this test; rejects after the fixture closes. */
|
|
13
|
+
start: () => Promise<TestClient>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Extend Vitest with a fresh mock and a lazy, automatically disposed client. Repeated `start()` calls share one
|
|
17
|
+
* promise. Await it to observe startup failures; cleanup waits for startup but does not rethrow its rejection.
|
|
18
|
+
* Missing mock responses still fail teardown even when no client was started. Page globals remain environment-owned.
|
|
19
|
+
* @param plan - roster and replacement modules, shared as configuration rather than as a running client.
|
|
20
|
+
* @param options - mount and readiness settings passed to `TestClient.start`.
|
|
21
|
+
* @returns Vitest's test function with test-scoped `mock` and `start` fixtures.
|
|
22
|
+
*/
|
|
23
|
+
export declare function createClientTest(plan: AssemblyPlan, options?: TestClientOptions): TestAPI<ClientTestFixtures>;
|
|
24
|
+
//# sourceMappingURL=vitest.d.ts.map
|
package/lib/types/fixtures.d.ts
CHANGED
|
@@ -44,6 +44,8 @@ export interface SessionFixture {
|
|
|
44
44
|
events?: readonly SessionEventLikeEntry[];
|
|
45
45
|
/** Whether the initial event window has an older page. */
|
|
46
46
|
hasMore?: boolean;
|
|
47
|
+
/** Optional shared initial-opening barrier for the fixture's Client generation. */
|
|
48
|
+
initialOpen?: (signal: AbortSignal) => void | Promise<void>;
|
|
47
49
|
}
|
|
48
50
|
/**
|
|
49
51
|
* A complete quiescent Session Controller snapshot.
|
package/lib/types/index.d.ts
CHANGED
|
@@ -16,9 +16,11 @@ import type { RenderResult } from '@testing-library/react';
|
|
|
16
16
|
import type { queries } from '@testing-library/dom';
|
|
17
17
|
import type { BoundFunctions } from '@testing-library/dom';
|
|
18
18
|
import { SlotRegistry } from '@deepseek-ai/dsh-client-ui-renderer/client';
|
|
19
|
+
import type { SessionReference } from '@deepseek-ai/dsh-api-session-controller/client';
|
|
19
20
|
import type { SessionId } from '@deepseek-ai/dsh-session/types';
|
|
20
21
|
import type { PanelInfo } from '@deepseek-ai/dsh-client-ui-layout/client';
|
|
21
|
-
import type { ChildrenDecl, ComposedProps, HostObservable, OwnerOf, RenderOpts, SlotComponent, SlotMap, SlotRenderer, SnapshotSelectorHook, StoreInstanceLike } from '@deepseek-ai/dsh-client-ui-slots';
|
|
22
|
+
import type { ChildrenDecl, ComposedProps, HostObservable, OwnerOf, RenderOpts, SlotComponent, SlotMap, SlotRenderer, SlotFactoryMap, SnapshotSelectorHook, StoredFactory, StoreInstanceLike } from '@deepseek-ai/dsh-client-ui-slots';
|
|
23
|
+
import { TestRemote } from './remote.ts';
|
|
22
24
|
import { TestSessions } from './sessions.ts';
|
|
23
25
|
import { TestWorkspaces } from './workspaces.ts';
|
|
24
26
|
import type { Stabilizer } from './fixtures.ts';
|
|
@@ -27,8 +29,6 @@ export { domSnapshotSerializer, registerDomSnapshotSerializer } from './snapshot
|
|
|
27
29
|
export { FixtureSession, TestSessions } from './sessions.ts';
|
|
28
30
|
export { stubSettingsScope } from './settings-scope.ts';
|
|
29
31
|
export type { StubSettingsScope } from './settings-scope.ts';
|
|
30
|
-
export { scriptedSettingsRemote } from './settings-remote.ts';
|
|
31
|
-
export type { ScriptedNamespace, ScriptedSettingsRemote } from './settings-remote.ts';
|
|
32
32
|
export { TestWorkspaces } from './workspaces.ts';
|
|
33
33
|
export { RemoteError, TestRemote } from './remote.ts';
|
|
34
34
|
export { chatSnapshot, conversationSnapshot, sessionSnapshot, workspaceSnapshot, } from './fixtures.ts';
|
|
@@ -46,6 +46,10 @@ export declare function bindSnapshotSelector<T>(source: HostObservable<T>): Snap
|
|
|
46
46
|
* @returns Slot renderer instance.
|
|
47
47
|
*/
|
|
48
48
|
export declare function createSlotRenderer(): SlotRenderer;
|
|
49
|
+
/** Per-view render options; the caller owns the explicitly supplied Session reference. */
|
|
50
|
+
export interface SlotTestRenderOptions extends RenderOpts {
|
|
51
|
+
readonly session?: SessionReference | undefined;
|
|
52
|
+
}
|
|
49
53
|
/**
|
|
50
54
|
* One rendered slot's local view, from {@link SlotTestRuntime.renderSlot}:
|
|
51
55
|
* the renderer's own `[data-slot]` outlet anchor is the snapshot root
|
|
@@ -62,8 +66,9 @@ export interface SlotView<K extends keyof SlotMap & string> {
|
|
|
62
66
|
* Replace the owner props and flush the re-render (the render-site update:
|
|
63
67
|
* in production the owner recomputes the share and React re-renders).
|
|
64
68
|
* @param owner - the next owner props share.
|
|
69
|
+
* @param opts - replacement render options and borrowed reference; omission keeps this view's options.
|
|
65
70
|
*/
|
|
66
|
-
update(owner: OwnerOf<K
|
|
71
|
+
update(owner: OwnerOf<K>, opts?: SlotTestRenderOptions): void;
|
|
67
72
|
}
|
|
68
73
|
/**
|
|
69
74
|
* Mounted feature plugin handle: the live fiber plus an act-wrapped,
|
|
@@ -81,8 +86,6 @@ export interface FeatureHandle {
|
|
|
81
86
|
}
|
|
82
87
|
/** Mutable fail-loud file-upload stub installed by {@link SlotTestRuntime}. */
|
|
83
88
|
export interface TestFileUpload {
|
|
84
|
-
/** Availability reported to the feature under test. */
|
|
85
|
-
available: boolean;
|
|
86
89
|
/** Test-supplied upload behavior; the default rejects every call. */
|
|
87
90
|
upload: (sessionId: SessionId, ...args: unknown[]) => Promise<unknown>;
|
|
88
91
|
}
|
|
@@ -125,8 +128,10 @@ export declare class SlotTestRuntime {
|
|
|
125
128
|
readonly slots: SlotRegistry;
|
|
126
129
|
/** The test-owned 'root' occupant. */
|
|
127
130
|
readonly root: TestRoot;
|
|
128
|
-
/**
|
|
131
|
+
/** Fixture catalog, explicit references, scoped contexts, and behavior faces. */
|
|
129
132
|
readonly sessions: TestSessions;
|
|
133
|
+
/** One Remote double shared by every feature mounted in this runtime. */
|
|
134
|
+
readonly remote: TestRemote;
|
|
130
135
|
/** Workspaces double (list observable, recorded intent actions). */
|
|
131
136
|
readonly workspaces: TestWorkspaces;
|
|
132
137
|
/** Test-owned panel selection used by the framework's usePanelInfo hook. */
|
|
@@ -188,20 +193,26 @@ export declare class SlotTestRuntime {
|
|
|
188
193
|
* slot of the same tree.
|
|
189
194
|
* @param key - a key declared through {@link SlotTestRuntime.declare}.
|
|
190
195
|
* @param owner - owner props share for the render site.
|
|
191
|
-
* @param opts - explicit
|
|
196
|
+
* @param opts - explicit entry selection and borrowed Session reference; retained by view updates.
|
|
192
197
|
* @returns the slot-local view (snapshot container, scoped queries, owner updates).
|
|
193
198
|
*/
|
|
194
|
-
renderSlot<K extends keyof SlotMap & string>(key: K, owner: OwnerOf<K>, opts?:
|
|
199
|
+
renderSlot<K extends keyof SlotMap & string>(key: K, owner: OwnerOf<K>, opts?: SlotTestRenderOptions): SlotView<K>;
|
|
195
200
|
/**
|
|
196
201
|
* Resolve the store instance the renderer would hand a slot's component
|
|
197
202
|
* (identity assertions, action-driven writes). Requires a prior
|
|
198
203
|
* {@link SlotTestRuntime.renderRoot} — the host face exists only inside the
|
|
199
204
|
* installed renderer, exactly as in production.
|
|
200
205
|
* @param key - slot key whose first entry declares the store.
|
|
201
|
-
* @param
|
|
206
|
+
* @param session - retained Session reference for session-scope slots; omit for root scope.
|
|
202
207
|
* @returns the live store instance.
|
|
203
208
|
*/
|
|
204
|
-
storeOf(key: keyof SlotMap & string,
|
|
209
|
+
storeOf(key: keyof SlotMap & string, session?: SessionReference): StoreInstanceLike;
|
|
210
|
+
/**
|
|
211
|
+
* Read one registered Factory definition for direct contract assertions.
|
|
212
|
+
* @param name - registered Factory name.
|
|
213
|
+
* @returns the live Factory definition.
|
|
214
|
+
*/
|
|
215
|
+
factoryOf(name: keyof SlotFactoryMap & string): StoredFactory;
|
|
205
216
|
/**
|
|
206
217
|
* Flush pending ledger/store notifications inside act — for mutations made
|
|
207
218
|
* outside the runtime's own methods (e.g. a direct `slots.register`).
|
package/lib/types/remote.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ export { RemoteError } from '@deepseek-ai/dsh-typert-protocol';
|
|
|
19
19
|
* against the real service.
|
|
20
20
|
*/
|
|
21
21
|
export declare class TestRemote {
|
|
22
|
+
private readonly ctx;
|
|
22
23
|
private readonly subscriptions;
|
|
23
24
|
/**
|
|
24
25
|
* Fixed Host facts mirrored from the production `ctx.remote.$host`. Plain
|
|
@@ -35,6 +36,13 @@ export declare class TestRemote {
|
|
|
35
36
|
* @param namespaces - scripted namespace faces reached as `ctx.remote.<name>`.
|
|
36
37
|
*/
|
|
37
38
|
constructor(ctx: Context, namespaces?: Readonly<Record<string, object>>);
|
|
39
|
+
/**
|
|
40
|
+
* Add scripted namespace faces to this Remote service.
|
|
41
|
+
* @param namespaces - scripted namespace faces reached as `ctx.remote.<name>`.
|
|
42
|
+
*/
|
|
43
|
+
provideNamespaces(namespaces: Readonly<Record<string, object>>): void;
|
|
44
|
+
private validateNamespaces;
|
|
45
|
+
private installNamespaces;
|
|
38
46
|
/**
|
|
39
47
|
* Deliver one forwarded host event to its subscribers, standing in for the
|
|
40
48
|
* carrier that owns the frame sink.
|
package/lib/types/sessions.d.ts
CHANGED
|
@@ -2,11 +2,18 @@
|
|
|
2
2
|
import type { Context } from '@deepseek-ai/cordis';
|
|
3
3
|
import type { AttachmentIdType } from '@deepseek-ai/dsh-attachment';
|
|
4
4
|
import { MutableSessionEventSource } from '@deepseek-ai/dsh-api-session-controller/client';
|
|
5
|
-
import type { AgentContext, ISessions, ProjectionsFace, SessionBinding, SessionFace, SessionListState, SessionEventLikeEntry, SessionLiveEventEntry, SessionSearchResultItem, SessionSnapshot, SessionSummary, SubmissionHandle } from '@deepseek-ai/dsh-api-session-controller/client';
|
|
5
|
+
import type { AgentContext, ISessions, ProjectionsFace, SessionBinding, SessionFace, SessionListState, SessionEventLikeEntry, SessionLiveEventEntry, SessionSearchResultItem, SessionReference, SessionRetainInfo, SessionRetainOptions, SessionSnapshot, SessionSummary, SessionTarget, SubmissionHandle } from '@deepseek-ai/dsh-api-session-controller/client';
|
|
6
6
|
import type { SubagentAddress } from '@deepseek-ai/dsh-subagent/client';
|
|
7
|
-
import type { SnapshotStore } from '@deepseek-ai/dsh-client-store';
|
|
7
|
+
import type { ObservableSnapshot, SnapshotStore } from '@deepseek-ai/dsh-client-store';
|
|
8
8
|
import type { SessionId } from '@deepseek-ai/dsh-session/types';
|
|
9
9
|
import type { SessionFixture, SessionFixtureSnapshot, Stabilizer } from './fixtures.ts';
|
|
10
|
+
declare module '@deepseek-ai/dsh-api-session-controller/client' {
|
|
11
|
+
interface SessionReferenceSourceMap {
|
|
12
|
+
testFixture: unknown;
|
|
13
|
+
testView: unknown;
|
|
14
|
+
testOperation: unknown;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
10
17
|
/**
|
|
11
18
|
* The fixture-backed session face: lifecycle reads delegate to the fixture's
|
|
12
19
|
* snapshot store; Session verbs are fail-loud stubs unless the
|
|
@@ -91,24 +98,29 @@ export declare class FixtureSession implements SessionFace {
|
|
|
91
98
|
}
|
|
92
99
|
/**
|
|
93
100
|
* Sessions test double behind the renderer host and feature injects: owns the
|
|
94
|
-
*
|
|
101
|
+
* catalog observable, scope minting through the production `createScope`,
|
|
95
102
|
* stable Controller bindings, and the session behavior face supplied per
|
|
96
103
|
* fixture. `ui-session` owns standard-source materialization.
|
|
97
104
|
*
|
|
98
105
|
* Implements the same ISessions face features receive as `ctx.sessions`, so
|
|
99
106
|
* a production face change breaks this double at compile time; the extra
|
|
100
|
-
* members (add/updateSessionSnapshot/event-window drivers/
|
|
107
|
+
* members (add/updateSessionSnapshot/event-window drivers/remove/
|
|
101
108
|
* behavior/calls/stubs) are bench-only surface.
|
|
102
109
|
*/
|
|
103
110
|
export declare class TestSessions implements ISessions {
|
|
104
111
|
private readonly stabilize;
|
|
105
112
|
private readonly rootCtx;
|
|
106
|
-
/** The useSessions
|
|
113
|
+
/** The useSessions catalog feed, independent of view ownership. */
|
|
107
114
|
readonly list: SnapshotStore<SessionListState>;
|
|
108
115
|
private readonly records;
|
|
116
|
+
private readonly generations;
|
|
117
|
+
private readonly addresses;
|
|
118
|
+
private readonly retentionStores;
|
|
119
|
+
private readonly pendingDrops;
|
|
120
|
+
private closed;
|
|
109
121
|
/** Calls observed on the service-level face, newest last. */
|
|
110
122
|
readonly calls: {
|
|
111
|
-
method: 'create' | '
|
|
123
|
+
method: 'create' | 'setSubagentCatalogOpen' | 'refreshSubagents' | 'refresh' | 'search' | 'fork';
|
|
112
124
|
args: unknown[];
|
|
113
125
|
}[];
|
|
114
126
|
/** The wire schema's `session.search` result bound (production parity). */
|
|
@@ -122,20 +134,24 @@ export declare class TestSessions implements ISessions {
|
|
|
122
134
|
*/
|
|
123
135
|
constructor(stabilize: Stabilizer, rootCtx: Context);
|
|
124
136
|
/**
|
|
125
|
-
* Add a
|
|
137
|
+
* Add a Session fixture to the catalog without retaining a generation.
|
|
126
138
|
* @param fixture - identity + snapshot/summary overrides + behavior face.
|
|
127
|
-
* @param opts - pass `current: false` to add without selecting.
|
|
128
139
|
* @returns the stable session id (branded view of `fixture.id`).
|
|
129
140
|
*/
|
|
130
|
-
add(fixture: SessionFixture
|
|
131
|
-
current?: boolean;
|
|
132
|
-
}): Promise<SessionId>;
|
|
141
|
+
add(fixture: SessionFixture): Promise<SessionId>;
|
|
133
142
|
/**
|
|
134
143
|
* Update Session Controller lifecycle state through an immer draft.
|
|
135
144
|
* @param id - session id.
|
|
136
145
|
* @param mutate - draft mutator.
|
|
137
146
|
*/
|
|
138
147
|
updateSessionSnapshot(id: string, mutate: (draft: SessionFixtureSnapshot) => void): Promise<void>;
|
|
148
|
+
/**
|
|
149
|
+
* Publish one complete projection value through the fixture Session face.
|
|
150
|
+
* @param id - session id.
|
|
151
|
+
* @param key - registered projection key.
|
|
152
|
+
* @param value - complete value for that key.
|
|
153
|
+
*/
|
|
154
|
+
setProjection(id: string, key: string, value: unknown): Promise<void>;
|
|
139
155
|
/**
|
|
140
156
|
* Replace a Session's complete contiguous event window.
|
|
141
157
|
* @param id - Session identity.
|
|
@@ -164,31 +180,33 @@ export declare class TestSessions implements ISessions {
|
|
|
164
180
|
*/
|
|
165
181
|
updateSummary(id: string, patch: Partial<Omit<SessionSummary, 'id'>>): Promise<void>;
|
|
166
182
|
/**
|
|
167
|
-
*
|
|
168
|
-
* @param id - session id to select, or undefined to clear.
|
|
169
|
-
*/
|
|
170
|
-
setCurrent(id: string | undefined): Promise<void>;
|
|
171
|
-
/**
|
|
172
|
-
* Remove a session: list row, scope fiber, and per-session store instances
|
|
173
|
-
* (with persisted state) die together — the same single lifecycle axis the
|
|
174
|
-
* production Client Sessions service drives on session death, minus staging.
|
|
183
|
+
* Remove a catalog row and mark its retained Session removed without releasing owners.
|
|
175
184
|
* @param id - session id.
|
|
176
185
|
*/
|
|
177
186
|
remove(id: string): Promise<void>;
|
|
178
187
|
/**
|
|
179
|
-
*
|
|
180
|
-
* the production `createScope`, so real `scopeOf`/scope-addressed services
|
|
181
|
-
* resolve it.
|
|
188
|
+
* Borrow the already-retained session-scoped Cordis context.
|
|
182
189
|
* @param id - session id.
|
|
183
|
-
* @returns the scoped context, or undefined
|
|
190
|
+
* @returns the scoped context, or undefined without a live reference.
|
|
184
191
|
*/
|
|
185
192
|
scope(id: string): AgentContext | undefined;
|
|
186
193
|
/**
|
|
187
194
|
* Session assembly binding (inject factories and provide resolvers receive it).
|
|
188
195
|
* @param id - session id.
|
|
189
|
-
* @returns
|
|
196
|
+
* @returns the live generation's binding, or undefined without a reference.
|
|
190
197
|
*/
|
|
191
198
|
binding(id: string): SessionBinding | undefined;
|
|
199
|
+
retain(target: SessionTarget, options?: SessionRetainOptions): SessionReference;
|
|
200
|
+
using<T>(target: SessionTarget, options: SessionRetainOptions, operation: (reference: SessionReference) => T | Promise<T>): Promise<T>;
|
|
201
|
+
retainInfo(id: SessionId): ObservableSnapshot<SessionRetainInfo>;
|
|
202
|
+
/**
|
|
203
|
+
* Retain one fixture Session until the supplied Cordis owner stops.
|
|
204
|
+
* @param ownerCtx - context whose disposal releases the reference.
|
|
205
|
+
* @param target - fixture Session identity or subagent address.
|
|
206
|
+
* @param options - reference source and optional readiness cancellation.
|
|
207
|
+
* @returns the owned reference immediately.
|
|
208
|
+
*/
|
|
209
|
+
retainFor(ownerCtx: Context, target: SessionTarget, options?: SessionRetainOptions): SessionReference;
|
|
192
210
|
/**
|
|
193
211
|
* Read the session scope tag off a context (service-method boundary mirror).
|
|
194
212
|
* @param ctx - any client context.
|
|
@@ -207,25 +225,14 @@ export declare class TestSessions implements ISessions {
|
|
|
207
225
|
* @param impl - implementation that must return an already-added fixture id.
|
|
208
226
|
*/
|
|
209
227
|
stubCreate(impl: (opts: Parameters<ISessions['create']>[0]) => Promise<SessionId>): void;
|
|
210
|
-
/** Create through the installed test behavior and require
|
|
228
|
+
/** Create through the installed test behavior and require a catalogued fixture. */
|
|
211
229
|
create(opts?: Parameters<ISessions['create']>[0]): Promise<SessionId>;
|
|
212
|
-
/**
|
|
213
|
-
* Service-level selection call (recorded, then applied to the list store
|
|
214
|
-
* synchronously — inject callbacks call this outside any act window; the
|
|
215
|
-
* store notify is microtask-batched so the next stabilized step observes it).
|
|
216
|
-
* @param id - session id.
|
|
217
|
-
*/
|
|
218
|
-
open(id: SessionId): void;
|
|
219
|
-
/** Open an existing fixture through its catalog address. */
|
|
220
|
-
openSubagent(address: SubagentAddress): void;
|
|
221
|
-
/** Resolve the current fixture's retained catalog address. */
|
|
230
|
+
/** Resolve a retained or catalog-derived address independently of a view. */
|
|
222
231
|
subagentAddress(id: SessionId): SubagentAddress | undefined;
|
|
223
232
|
/** Record catalog consumption; fixture callers drive snapshots explicitly. */
|
|
224
233
|
setSubagentCatalogOpen(parentSessionId: SessionId, open: boolean): void;
|
|
225
234
|
/** Record a catalog refresh; fixture callers drive snapshots explicitly. */
|
|
226
235
|
refreshSubagents(parentSessionId: SessionId): Promise<void>;
|
|
227
|
-
/** Clear the current selection (recorded; the production no-session flow). */
|
|
228
|
-
clear(): void;
|
|
229
236
|
/** Record a list refresh; fixture callers publish list state explicitly. */
|
|
230
237
|
refresh(): Promise<void>;
|
|
231
238
|
/**
|
|
@@ -265,7 +272,14 @@ export declare class TestSessions implements ISessions {
|
|
|
265
272
|
behavior(id: string): FixtureSession;
|
|
266
273
|
/** Dispose minted scope fibers (runtime dispose path). */
|
|
267
274
|
disposeScopes(): Promise<void>;
|
|
268
|
-
private
|
|
275
|
+
private resolveTarget;
|
|
276
|
+
private retainGeneration;
|
|
277
|
+
private retentionSnapshot;
|
|
278
|
+
private publishRetention;
|
|
279
|
+
private materialize;
|
|
280
|
+
private startOpening;
|
|
281
|
+
private drop;
|
|
282
|
+
private drainDrops;
|
|
269
283
|
private require;
|
|
270
284
|
}
|
|
271
285
|
//# sourceMappingURL=sessions.d.ts.map
|
|
@@ -84,6 +84,12 @@ export declare class TestWorkspaces implements IWorkspaces {
|
|
|
84
84
|
* @param sessionId - session to archive.
|
|
85
85
|
*/
|
|
86
86
|
archiveSession(sessionId: SessionId): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Unarchive a session (recorded). The default mirrors the production face's
|
|
89
|
+
* observable effect: the id leaves the list state's archive set.
|
|
90
|
+
* @param sessionId - session to unarchive.
|
|
91
|
+
*/
|
|
92
|
+
unarchiveSession(sessionId: SessionId): Promise<void>;
|
|
87
93
|
}
|
|
88
94
|
export {};
|
|
89
95
|
//# sourceMappingURL=workspaces.d.ts.map
|