@deepseek-ai/dsh-client-test-runtime 0.0.1-rc.1 → 0.0.1-rc.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/lib/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Context, Inject } from "@deepseek-ai/cordis";
2
2
  import { Fragment, createElement, useSyncExternalStore } from "react";
3
3
  import { act, render, within } from "@testing-library/react";
4
- import { ConversationEventRegistry, ConversationViewRegistry, EMPTY_CHAT_SNAPSHOT, SessionProvideChannel, SlotsService, createScope, createSnapshotStore, scopeOf } from "@deepseek-ai/dsh-client-runtime/client";
4
+ import { ConversationEventRegistry, ConversationViewRegistry, EMPTY_CHAT_SNAPSHOT, EMPTY_CONVERSATION_VIEWS, SessionProvideChannel, SlotsService, createScope, createSnapshotStore, scopeOf } from "@deepseek-ai/dsh-client-runtime/client";
5
5
  import { createSlotRenderer } from "@deepseek-ai/dsh-client-web-react";
6
6
  import { afterEach, beforeEach, expect, vi } from "vitest";
7
7
  import { SESSION_SEARCH_RESULT_LIMIT } from "@deepseek-ai/dsh-host-apiproxy/api";
@@ -90,6 +90,7 @@ function registerDomSnapshotSerializer() {
90
90
  function conversationSnapshot(sessionId) {
91
91
  return {
92
92
  sessionId,
93
+ views: EMPTY_CONVERSATION_VIEWS,
93
94
  chat: EMPTY_CHAT_SNAPSHOT,
94
95
  nodes: [],
95
96
  turnTimings: /* @__PURE__ */ new Map(),
@@ -289,6 +290,7 @@ var TestSessions = class {
289
290
  current: void 0,
290
291
  phase: "ready",
291
292
  subagentsByParent: {},
293
+ tasksBySession: {},
292
294
  currentAddress: void 0
293
295
  });
294
296
  this.channel = new SessionProvideChannel({
@@ -876,12 +878,15 @@ function stubSettingsScope() {
876
878
  let snapshot = {
877
879
  status: "loading",
878
880
  value: void 0,
881
+ base: void 0,
882
+ user: void 0,
879
883
  revision: void 0,
880
884
  writable: false,
881
885
  mode: "host"
882
886
  };
883
887
  const listeners = /* @__PURE__ */ new Set();
884
888
  const set = vi.fn(() => Promise.resolve());
889
+ const unset = vi.fn(() => Promise.resolve());
885
890
  return {
886
891
  scope: {
887
892
  getSnapshot: () => snapshot,
@@ -891,9 +896,11 @@ function stubSettingsScope() {
891
896
  listeners.delete(listener);
892
897
  };
893
898
  },
894
- set
899
+ set,
900
+ unset
895
901
  },
896
902
  set,
903
+ unset,
897
904
  listenerCount: () => listeners.size,
898
905
  publish: (next) => {
899
906
  snapshot = {
@@ -905,6 +912,69 @@ function stubSettingsScope() {
905
912
  };
906
913
  }
907
914
  //#endregion
915
+ //#region lib/types/remote.js
916
+ /**
917
+ * Remote service test double for the forwarded-event path. Feature specs need
918
+ * `ctx.remote.$on` to exist (their plugins inject `remote`) and need forwarded
919
+ * host events to reach those subscribers, but not the generated namespaces or
920
+ * the wire — so this double implements subscription and dispatch only.
921
+ *
922
+ * Dispatch is driven the same way production drives it: `client/runtime` owns the
923
+ * host frame sink and hands each decoded `host/remote-event` frame to
924
+ * `$dispatch`. A spec therefore exercises its refresh chains by calling
925
+ * `$dispatch(name, args)` on this double.
926
+ *
927
+ * `$mount` rejects: a spec that reaches a generated namespace through this
928
+ * double has outgrown it and needs the real Client Remote service.
929
+ *
930
+ * One deliberate asymmetry with production: a throwing listener propagates out
931
+ * of the emit instead of being contained and logged, so a spec cannot lean on
932
+ * this double for the containment guarantee `$on` documents — assert that
933
+ * against the real service.
934
+ */
935
+ var TestRemote = class {
936
+ subscriptions = /* @__PURE__ */ new Map();
937
+ /**
938
+ * Register the double as `ctx.remote`.
939
+ * @param ctx - the spec's root Context.
940
+ */
941
+ constructor(ctx) {
942
+ ctx.provide("remote", this);
943
+ }
944
+ /**
945
+ * Deliver one forwarded host event to its subscribers, standing in for the
946
+ * carrier that owns the frame sink.
947
+ * @param event - forwarded host event name.
948
+ * @param args - the Host argument list, verbatim.
949
+ */
950
+ $dispatch(event, args) {
951
+ const listeners = this.subscriptions.get(event);
952
+ if (listeners === void 0) return;
953
+ for (const listener of [...listeners]) listener(...args);
954
+ }
955
+ /**
956
+ * Subscribe to one forwarded host event.
957
+ * @param event - forwarded host event name.
958
+ * @param listener - receives the Host argument list verbatim.
959
+ * @returns disposer removing this subscription.
960
+ */
961
+ $on(event, listener) {
962
+ const listeners = this.subscriptions.get(event) ?? /* @__PURE__ */ new Set();
963
+ this.subscriptions.set(event, listeners);
964
+ listeners.add(listener);
965
+ return () => {
966
+ listeners.delete(listener);
967
+ };
968
+ }
969
+ /**
970
+ * Generated-namespace mount, unsupported by this double.
971
+ * @returns never; always rejects.
972
+ */
973
+ $mount() {
974
+ return Promise.reject(/* @__PURE__ */ new Error("TestRemote: $mount needs the real Client Remote service"));
975
+ }
976
+ };
977
+ //#endregion
908
978
  //#region lib/types/translate.js
909
979
  /**
910
980
  * Test double of the locale lookup chain: a translate stub over plain
@@ -1256,4 +1326,4 @@ var SlotTestRuntime = class SlotTestRuntime {
1256
1326
  }
1257
1327
  };
1258
1328
  //#endregion
1259
- export { FixtureSession, SlotTestRuntime, TestRoot, TestSessions, TestWorkspaces, conversationSnapshot, domSnapshotSerializer, makeTranslate, registerDomSnapshotSerializer, stubSettingsScope, usePinnedBrowserLanguages, workspaceListState };
1329
+ export { FixtureSession, SlotTestRuntime, TestRemote, TestRoot, TestSessions, TestWorkspaces, conversationSnapshot, domSnapshotSerializer, makeTranslate, registerDomSnapshotSerializer, stubSettingsScope, usePinnedBrowserLanguages, workspaceListState };
@@ -25,6 +25,7 @@ export { FixtureSession, TestSessions } from './sessions.ts';
25
25
  export { stubSettingsScope } from './settings-scope.ts';
26
26
  export type { StubSettingsScope } from './settings-scope.ts';
27
27
  export { TestWorkspaces } from './workspaces.ts';
28
+ export { TestRemote } from './remote.ts';
28
29
  export { conversationSnapshot, workspaceListState } from './fixtures.ts';
29
30
  export type { SessionBehaviorOverrides, SessionFixture, Stabilizer } from './fixtures.ts';
30
31
  export { makeTranslate } from './translate.ts';
@@ -0,0 +1,49 @@
1
+ /** Test-owned Remote face: `$on` subscriptions driven by the internal forwarded-event plumbing. */
2
+ import type { Context } from '@deepseek-ai/cordis';
3
+ /**
4
+ * Remote service test double for the forwarded-event path. Feature specs need
5
+ * `ctx.remote.$on` to exist (their plugins inject `remote`) and need forwarded
6
+ * host events to reach those subscribers, but not the generated namespaces or
7
+ * the wire — so this double implements subscription and dispatch only.
8
+ *
9
+ * Dispatch is driven the same way production drives it: `client/runtime` owns the
10
+ * host frame sink and hands each decoded `host/remote-event` frame to
11
+ * `$dispatch`. A spec therefore exercises its refresh chains by calling
12
+ * `$dispatch(name, args)` on this double.
13
+ *
14
+ * `$mount` rejects: a spec that reaches a generated namespace through this
15
+ * double has outgrown it and needs the real Client Remote service.
16
+ *
17
+ * One deliberate asymmetry with production: a throwing listener propagates out
18
+ * of the emit instead of being contained and logged, so a spec cannot lean on
19
+ * this double for the containment guarantee `$on` documents — assert that
20
+ * against the real service.
21
+ */
22
+ export declare class TestRemote {
23
+ private readonly subscriptions;
24
+ /**
25
+ * Register the double as `ctx.remote`.
26
+ * @param ctx - the spec's root Context.
27
+ */
28
+ constructor(ctx: Context);
29
+ /**
30
+ * Deliver one forwarded host event to its subscribers, standing in for the
31
+ * carrier that owns the frame sink.
32
+ * @param event - forwarded host event name.
33
+ * @param args - the Host argument list, verbatim.
34
+ */
35
+ $dispatch(event: string, args: readonly unknown[]): void;
36
+ /**
37
+ * Subscribe to one forwarded host event.
38
+ * @param event - forwarded host event name.
39
+ * @param listener - receives the Host argument list verbatim.
40
+ * @returns disposer removing this subscription.
41
+ */
42
+ $on(event: string, listener: (...args: never[]) => void): () => void;
43
+ /**
44
+ * Generated-namespace mount, unsupported by this double.
45
+ * @returns never; always rejects.
46
+ */
47
+ $mount(): Promise<() => Promise<void>>;
48
+ }
49
+ //# sourceMappingURL=remote.d.ts.map
@@ -7,6 +7,8 @@ export interface StubSettingsScope<T> {
7
7
  scope: SettingsScope<T>;
8
8
  /** Spy behind `scope.set`; resolves immediately. */
9
9
  set: ReturnType<typeof vi.fn>;
10
+ /** Spy behind `scope.unset`; resolves immediately. */
11
+ unset: ReturnType<typeof vi.fn>;
10
12
  /** @returns how many listeners are currently subscribed (disposal assertions). */
11
13
  listenerCount(): number;
12
14
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-client-test-runtime",
3
3
  "description": "jsdom slot test runtime: real Cordis Context + SlotsService + web-react renderer with test-owned session/workspace doubles for feature specs",
4
- "version": "0.0.1-rc.1",
4
+ "version": "0.0.1-rc.2",
5
5
  "publishConfig": {
6
6
  "access": "restricted"
7
7
  },
@@ -34,24 +34,24 @@
34
34
  "peerDependencies": {
35
35
  "react": "^18.2.0",
36
36
  "react-dom": "^18.2.0",
37
- "@deepseek-ai/dsh-client-runtime": "^0.0.1-rc.1",
38
- "@deepseek-ai/dsh-client-ui-slots": "^0.0.1-rc.1",
39
- "@deepseek-ai/dsh-client-web-react": "^0.0.1-rc.1",
40
- "@deepseek-ai/dsh-host-apiproxy": "^0.0.1-rc.1",
41
- "@deepseek-ai/cordis": "^4.0.1-rc.1",
42
- "@deepseek-ai/dsh-invariants": "^0.0.1-rc.1"
37
+ "@deepseek-ai/dsh-client-runtime": "^0.0.1-rc.2",
38
+ "@deepseek-ai/dsh-client-ui-slots": "^0.0.1-rc.2",
39
+ "@deepseek-ai/dsh-host-apiproxy": "^0.0.1-rc.2",
40
+ "@deepseek-ai/dsh-client-web-react": "^0.0.1-rc.2",
41
+ "@deepseek-ai/dsh-invariants": "^0.0.1-rc.2",
42
+ "@deepseek-ai/cordis": "^4.0.1-rc.1"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@types/react": "~18.3.1",
46
46
  "@types/react-dom": "~18.3.0",
47
47
  "react": "^18.2.0",
48
48
  "react-dom": "^18.2.0",
49
- "@deepseek-ai/dsh-client-runtime": "^0.0.1-rc.1",
50
- "@deepseek-ai/dsh-client-web-react": "^0.0.1-rc.1",
51
- "@deepseek-ai/dsh-host-apiproxy": "^0.0.1-rc.1",
52
- "@deepseek-ai/dsh-client-ui-slots": "^0.0.1-rc.1",
53
- "@deepseek-ai/cordis": "^4.0.1-rc.1",
54
- "@deepseek-ai/dsh-invariants": "^0.0.1-rc.1"
49
+ "@deepseek-ai/dsh-client-runtime": "^0.0.1-rc.2",
50
+ "@deepseek-ai/dsh-client-ui-slots": "^0.0.1-rc.2",
51
+ "@deepseek-ai/dsh-host-apiproxy": "^0.0.1-rc.2",
52
+ "@deepseek-ai/dsh-client-web-react": "^0.0.1-rc.2",
53
+ "@deepseek-ai/dsh-invariants": "^0.0.1-rc.2",
54
+ "@deepseek-ai/cordis": "^4.0.1-rc.1"
55
55
  },
56
56
  "files": [
57
57
  "lib/index.js",