dsh-input-traffic 0.6.1 → 0.7.3

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.
Files changed (53) hide show
  1. package/CHANGELOG.ja.md +94 -94
  2. package/CHANGELOG.ko.md +94 -94
  3. package/CHANGELOG.md +39 -18
  4. package/INSTALL.ja.md +151 -151
  5. package/INSTALL.ko.md +151 -151
  6. package/README.en.md +9 -7
  7. package/README.ja.md +192 -187
  8. package/README.ko.md +186 -181
  9. package/README.md +9 -6
  10. package/dsh.plugin.json +16 -16
  11. package/lib/client.js +725 -175
  12. package/lib/client.js.map +1 -1
  13. package/lib/index.js +195 -3
  14. package/lib/types/bridge.d.ts +45 -0
  15. package/lib/types/bridge.d.ts.map +1 -0
  16. package/lib/types/bridge.js +130 -0
  17. package/lib/types/bridge.js.map +1 -0
  18. package/lib/types/client/bridge-scope.d.ts +38 -0
  19. package/lib/types/client/bridge-scope.d.ts.map +1 -0
  20. package/lib/types/client/bridge-scope.js +81 -0
  21. package/lib/types/client/bridge-scope.js.map +1 -0
  22. package/lib/types/client/compat.d.ts +68 -0
  23. package/lib/types/client/compat.d.ts.map +1 -0
  24. package/lib/types/client/compat.js +47 -0
  25. package/lib/types/client/compat.js.map +1 -0
  26. package/lib/types/client/family-card.d.ts +2 -1
  27. package/lib/types/client/family-card.d.ts.map +1 -1
  28. package/lib/types/client/family-card.js +12 -2
  29. package/lib/types/client/family-card.js.map +1 -1
  30. package/lib/types/client/index.d.ts +7 -1
  31. package/lib/types/client/index.d.ts.map +1 -1
  32. package/lib/types/client/index.js +63 -20
  33. package/lib/types/client/index.js.map +1 -1
  34. package/lib/types/client/locales.d.ts +12 -0
  35. package/lib/types/client/locales.d.ts.map +1 -1
  36. package/lib/types/client/locales.js +277 -0
  37. package/lib/types/client/locales.js.map +1 -1
  38. package/lib/types/client/steer-queue-dock.d.ts.map +1 -1
  39. package/lib/types/client/steer-queue-dock.js.map +1 -1
  40. package/lib/types/index.d.ts +16 -5
  41. package/lib/types/index.d.ts.map +1 -1
  42. package/lib/types/index.js +25 -2
  43. package/lib/types/index.js.map +1 -1
  44. package/locale/de.json +1 -0
  45. package/locale/en.json +1 -0
  46. package/locale/es.json +1 -0
  47. package/locale/fr.json +1 -0
  48. package/locale/it.json +1 -0
  49. package/locale/ja.json +1 -0
  50. package/locale/ko.json +1 -0
  51. package/locale/ru.json +1 -0
  52. package/locale/zh.json +1 -0
  53. package/package.json +22 -42
package/lib/index.js CHANGED
@@ -1,5 +1,197 @@
1
+ //#region lib/types/bridge.js
2
+ /** Route pair for one settings ns — client and server must derive identically. */
3
+ function bridgeRoutesFor(ns) {
4
+ return {
5
+ describe: `/api/${ns}/settings/describe`,
6
+ mutate: `/api/${ns}/settings/mutate`
7
+ };
8
+ }
9
+ function readJsonBody(reqRaw, limit = 262144) {
10
+ const req = reqRaw;
11
+ return new Promise((resolve, reject) => {
12
+ const chunks = [];
13
+ let size = 0;
14
+ req.on("data", (chunk) => {
15
+ const buf = chunk;
16
+ size += buf.length;
17
+ if (size > limit) {
18
+ reject(/* @__PURE__ */ new Error("bridge body too large"));
19
+ req.resume?.();
20
+ return;
21
+ }
22
+ chunks.push(buf);
23
+ });
24
+ req.on("end", () => {
25
+ const raw = Buffer.concat(chunks).toString("utf8");
26
+ if (raw === "") {
27
+ resolve({});
28
+ return;
29
+ }
30
+ try {
31
+ resolve(JSON.parse(raw));
32
+ } catch (e) {
33
+ reject(e instanceof Error ? e : new Error(String(e)));
34
+ }
35
+ });
36
+ req.on("error", reject);
37
+ });
38
+ }
39
+ function sendJson(res, code, body) {
40
+ res.writeHead(code, {
41
+ "content-type": "application/json; charset=utf-8",
42
+ "cache-control": "no-cache"
43
+ });
44
+ res.end(JSON.stringify(body));
45
+ }
46
+ function isConflict(e) {
47
+ return e instanceof Error && /conflict|revision/i.test(e.message);
48
+ }
49
+ function registerSettingsBridgeRoutes(server, getSettingsSvc, ns) {
50
+ if (typeof server !== "object" || server === null) return [];
51
+ const ws = typeof server.register === "function" ? server : void 0;
52
+ if (ws === void 0) return [];
53
+ const offs = [];
54
+ const routes = bridgeRoutesFor(ns);
55
+ offs.push(ws.register({
56
+ kind: "exact",
57
+ path: routes.describe,
58
+ handler: (rawReq, rawRes) => {
59
+ const req = rawReq;
60
+ const res = rawRes;
61
+ if (req.method !== "POST") {
62
+ sendJson(res, 405, {
63
+ ok: false,
64
+ code: "method-not-allowed"
65
+ });
66
+ return;
67
+ }
68
+ const svc = getSettingsSvc();
69
+ if (svc === void 0 || typeof svc.describe !== "function") {
70
+ sendJson(res, 200, {
71
+ ok: false,
72
+ code: "settings-unavailable",
73
+ message: "settings service not resolved yet"
74
+ });
75
+ return;
76
+ }
77
+ try {
78
+ const descriptor = svc.describe({ redactSecrets: true }).find((d) => d.ns === ns);
79
+ if (descriptor === void 0) {
80
+ sendJson(res, 200, {
81
+ ok: false,
82
+ code: "ns-not-registered",
83
+ message: `settings namespace "${ns}" is not registered`
84
+ });
85
+ return;
86
+ }
87
+ sendJson(res, 200, {
88
+ ok: true,
89
+ value: {
90
+ descriptor,
91
+ writable: svc.writable !== false
92
+ }
93
+ });
94
+ } catch (e) {
95
+ sendJson(res, 200, {
96
+ ok: false,
97
+ code: "internal",
98
+ message: e instanceof Error ? e.message : String(e)
99
+ });
100
+ }
101
+ }
102
+ }));
103
+ offs.push(ws.register({
104
+ kind: "exact",
105
+ path: routes.mutate,
106
+ handler: (rawReq, rawRes) => {
107
+ const req = rawReq;
108
+ const res = rawRes;
109
+ if (req.method !== "POST") {
110
+ sendJson(res, 405, {
111
+ ok: false,
112
+ code: "method-not-allowed"
113
+ });
114
+ return;
115
+ }
116
+ const svc = getSettingsSvc();
117
+ const mutate = svc === void 0 ? void 0 : svc.mutate;
118
+ if (typeof mutate !== "function") {
119
+ sendJson(res, 200, {
120
+ ok: false,
121
+ code: "settings-unavailable",
122
+ message: "settings service mutate not available"
123
+ });
124
+ return;
125
+ }
126
+ readJsonBody(req).then((body) => {
127
+ const ops = body.ops;
128
+ if (!Array.isArray(ops) || ops.some((op) => !op || typeof op !== "object" || !(op.op in {
129
+ set: 1,
130
+ unset: 1
131
+ }))) {
132
+ sendJson(res, 200, {
133
+ ok: false,
134
+ code: "settings-rejected",
135
+ message: "malformed bridge mutate ops"
136
+ });
137
+ return;
138
+ }
139
+ const expectedRevision = typeof body.expectedRevision === "number" ? body.expectedRevision : void 0;
140
+ mutate.call(svc, ns, ops, expectedRevision).then(() => {
141
+ const descriptor = svc.describe({ redactSecrets: true }).find((d) => d.ns === ns);
142
+ if (descriptor === void 0) {
143
+ sendJson(res, 200, {
144
+ ok: false,
145
+ code: "internal",
146
+ message: `namespace "${ns}" disposed after mutate`
147
+ });
148
+ return;
149
+ }
150
+ sendJson(res, 200, {
151
+ ok: true,
152
+ value: { descriptor }
153
+ });
154
+ }).catch((e) => {
155
+ sendJson(res, 200, isConflict(e) ? {
156
+ ok: false,
157
+ code: "settings-conflict",
158
+ message: e instanceof Error ? e.message : String(e)
159
+ } : {
160
+ ok: false,
161
+ code: "internal",
162
+ message: e instanceof Error ? e.message : String(e)
163
+ });
164
+ });
165
+ }).catch((e) => {
166
+ sendJson(res, 200, {
167
+ ok: false,
168
+ code: "bad-request",
169
+ message: e instanceof Error ? e.message : String(e)
170
+ });
171
+ });
172
+ }
173
+ }));
174
+ return offs;
175
+ }
176
+ //#endregion
1
177
  //#region lib/types/index.js
2
- /** @param ctx - host-side context; intentionally unused (client-plugin shape). */
3
- function apply(ctx) {}
178
+ /** The settings namespace the browser half pins (`ui-conversation.busyEnter`). */
179
+ const BRIDGE_NS = "ui-conversation";
180
+ /** webServer hosts the bridge route pair. */
181
+ const inject = ["webServer"];
182
+ /** @param ctx - host-side context; registers the bridge route pair. */
183
+ function apply(ctx) {
184
+ const settingsRef = {};
185
+ ctx.inject(["settings"], (child) => {
186
+ settingsRef.svc = child.settings;
187
+ });
188
+ ctx.effect(() => {
189
+ const injected = ctx;
190
+ const offs = registerSettingsBridgeRoutes(injected.webServer ?? injected.get?.("webServer"), () => settingsRef.svc, BRIDGE_NS);
191
+ return () => {
192
+ for (const off of offs) off();
193
+ };
194
+ }, "dsh-input-traffic: settings bridge routes");
195
+ }
4
196
  //#endregion
5
- export { apply };
197
+ export { apply, inject };
@@ -0,0 +1,45 @@
1
+ /**
2
+ * settings bridge — T20-b port from dsh-perm-gate (5260fe6 generalized form).
3
+ *
4
+ * The plugin is a pure client takeover on every host line, but its durable
5
+ * data plane (the `ui-conversation` busy-Enter pin) rides the client settings
6
+ * handles that are generation-exclusive: `configForms` (0.1.7+) works,
7
+ * `settingsScope` (≤0.1.5) resolves to nothing (the A2 dead end), so on old
8
+ * lines both the family card and the pin itself silently no-op. This bridge
9
+ * gives the browser half a same-origin HTTP data plane backed by the HOST's
10
+ * settings service — reads = svc.describe of our ns, writes = svc.mutate ops.
11
+ * No second copy of state: the service stays the single source of truth.
12
+ * Guards: POST-only, ns fixed at registration, optimistic concurrency via
13
+ * expectedRevision. The 0.1.0 host settings service carries the full
14
+ * describe/mutate/redactSecrets surface (lib/index.js verified), so the
15
+ * oldest line needs no fallback path.
16
+ *
17
+ * Data consumer = client BridgeDocHandle (src/client/bridge-scope.ts) — the
18
+ * T13b dual-track: native handle first (0.1.7+), this bridge underneath.
19
+ * Routes derive from the ns (bridgeRoutesFor) so the URL contract cannot
20
+ * drift between the two halves; the parity test pins both derivations
21
+ * character-for-character.
22
+ */
23
+ interface SettingsServiceLike {
24
+ update?(ns: string, patch: object): Promise<void>;
25
+ describe?(o?: {
26
+ redactSecrets?: boolean;
27
+ }): Array<{
28
+ ns: unknown;
29
+ [k: string]: unknown;
30
+ }>;
31
+ mutate?(ns: string, ops: Array<{
32
+ op: string;
33
+ path: string[];
34
+ value?: unknown;
35
+ }>, expectedRevision?: number): Promise<unknown>;
36
+ writable?: boolean;
37
+ }
38
+ /** Route pair for one settings ns — client and server must derive identically. */
39
+ export declare function bridgeRoutesFor(ns: string): {
40
+ describe: string;
41
+ mutate: string;
42
+ };
43
+ export declare function registerSettingsBridgeRoutes(server: unknown, getSettingsSvc: () => SettingsServiceLike | undefined, ns: string): Array<() => void>;
44
+ export {};
45
+ //# sourceMappingURL=bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../src/bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,UAAU,mBAAmB;IAC3B,MAAM,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACjD,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,KAAK,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC,CAAA;IACxF,MAAM,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,EAAE,gBAAgB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC7H,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAEhF;AAuCD,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,OAAO,EACf,cAAc,EAAE,MAAM,mBAAmB,GAAG,SAAS,EACrD,EAAE,EAAE,MAAM,GACT,KAAK,CAAC,MAAM,IAAI,CAAC,CA6EnB"}
@@ -0,0 +1,130 @@
1
+ /** Route pair for one settings ns — client and server must derive identically. */
2
+ export function bridgeRoutesFor(ns) {
3
+ return { describe: `/api/${ns}/settings/describe`, mutate: `/api/${ns}/settings/mutate` };
4
+ }
5
+ function readJsonBody(reqRaw, limit = 256 * 1024) {
6
+ const req = reqRaw;
7
+ return new Promise((resolve, reject) => {
8
+ const chunks = [];
9
+ let size = 0;
10
+ req.on('data', (chunk) => {
11
+ const buf = chunk;
12
+ size += buf.length;
13
+ if (size > limit) {
14
+ reject(new Error('bridge body too large'));
15
+ req.resume?.();
16
+ return;
17
+ }
18
+ chunks.push(buf);
19
+ });
20
+ req.on('end', () => {
21
+ const raw = Buffer.concat(chunks).toString('utf8');
22
+ if (raw === '') {
23
+ resolve({});
24
+ return;
25
+ }
26
+ try {
27
+ resolve(JSON.parse(raw));
28
+ }
29
+ catch (e) {
30
+ reject(e instanceof Error ? e : new Error(String(e)));
31
+ }
32
+ });
33
+ req.on('error', reject);
34
+ });
35
+ }
36
+ function sendJson(res, code, body) {
37
+ res.writeHead(code, { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-cache' });
38
+ res.end(JSON.stringify(body));
39
+ }
40
+ function isConflict(e) {
41
+ return e instanceof Error && /conflict|revision/i.test(e.message);
42
+ }
43
+ export function registerSettingsBridgeRoutes(server, getSettingsSvc, ns) {
44
+ if (typeof server !== 'object' || server === null)
45
+ return [];
46
+ const ws = typeof server.register === 'function' ? server : undefined;
47
+ if (ws === undefined)
48
+ return [];
49
+ const offs = [];
50
+ const routes = bridgeRoutesFor(ns);
51
+ offs.push(ws.register({
52
+ kind: 'exact',
53
+ path: routes.describe,
54
+ handler: (rawReq, rawRes) => {
55
+ const req = rawReq;
56
+ const res = rawRes;
57
+ if (req.method !== 'POST') {
58
+ sendJson(res, 405, { ok: false, code: 'method-not-allowed' });
59
+ return;
60
+ }
61
+ const svc = getSettingsSvc();
62
+ if (svc === undefined || typeof svc.describe !== 'function') {
63
+ sendJson(res, 200, { ok: false, code: 'settings-unavailable', message: 'settings service not resolved yet' });
64
+ return;
65
+ }
66
+ try {
67
+ const descriptor = svc
68
+ .describe({ redactSecrets: true })
69
+ .find((d) => d.ns === ns);
70
+ if (descriptor === undefined) {
71
+ sendJson(res, 200, { ok: false, code: 'ns-not-registered', message: `settings namespace "${ns}" is not registered` });
72
+ return;
73
+ }
74
+ sendJson(res, 200, { ok: true, value: { descriptor, writable: svc.writable !== false } });
75
+ }
76
+ catch (e) {
77
+ sendJson(res, 200, { ok: false, code: 'internal', message: e instanceof Error ? e.message : String(e) });
78
+ }
79
+ },
80
+ }));
81
+ offs.push(ws.register({
82
+ kind: 'exact',
83
+ path: routes.mutate,
84
+ handler: (rawReq, rawRes) => {
85
+ const req = rawReq;
86
+ const res = rawRes;
87
+ if (req.method !== 'POST') {
88
+ sendJson(res, 405, { ok: false, code: 'method-not-allowed' });
89
+ return;
90
+ }
91
+ const svc = getSettingsSvc();
92
+ const mutate = svc === undefined ? undefined : svc.mutate;
93
+ if (typeof mutate !== 'function') {
94
+ sendJson(res, 200, { ok: false, code: 'settings-unavailable', message: 'settings service mutate not available' });
95
+ return;
96
+ }
97
+ readJsonBody(req).then((body) => {
98
+ const ops = body.ops;
99
+ if (!Array.isArray(ops) || ops.some((op) => !op || typeof op !== 'object' || !(op.op in { set: 1, unset: 1 }))) {
100
+ sendJson(res, 200, { ok: false, code: 'settings-rejected', message: 'malformed bridge mutate ops' });
101
+ return;
102
+ }
103
+ const expectedRevision = typeof body.expectedRevision === 'number' ? body.expectedRevision : undefined;
104
+ mutate
105
+ .call(svc, ns, ops, expectedRevision)
106
+ .then(() => {
107
+ // Successful mutate re-describes: writes stay funneled through the
108
+ // host service, no shadow state anywhere.
109
+ const descriptor = svc
110
+ .describe({ redactSecrets: true })
111
+ .find((d) => d.ns === ns);
112
+ if (descriptor === undefined) {
113
+ sendJson(res, 200, { ok: false, code: 'internal', message: `namespace "${ns}" disposed after mutate` });
114
+ return;
115
+ }
116
+ sendJson(res, 200, { ok: true, value: { descriptor } });
117
+ })
118
+ .catch((e) => {
119
+ sendJson(res, 200, isConflict(e)
120
+ ? { ok: false, code: 'settings-conflict', message: e instanceof Error ? e.message : String(e) }
121
+ : { ok: false, code: 'internal', message: e instanceof Error ? e.message : String(e) });
122
+ });
123
+ }).catch((e) => {
124
+ sendJson(res, 200, { ok: false, code: 'bad-request', message: e instanceof Error ? e.message : String(e) });
125
+ });
126
+ },
127
+ }));
128
+ return offs;
129
+ }
130
+ //# sourceMappingURL=bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../src/bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * BridgeDocHandle — T20-b port from dsh-perm-gate (bridge-scope.ts, the
3
+ * client half of the settings bridge).
4
+ *
5
+ * Shape-compatible with the native durable-settings handle (configForms.get /
6
+ * settingsScope.bind subset): getSnapshot/subscribe/set. Reads POST
7
+ * /api/<ns>/settings/describe, writes POST …/mutate (ops forwarded to the
8
+ * host settings service); a successful write re-describes and refreshes the
9
+ * snapshot (optimistic refresh, no local second copy of state — the service
10
+ * stays authoritative). The initial describe fetch starts at construction;
11
+ * the snapshot is `pending` until it lands, and the family card renders its
12
+ * pinned default meanwhile.
13
+ *
14
+ * The route derivation must stay character-identical to the server side
15
+ * (src/bridge.ts bridgeRoutesFor); the client tsconfig only includes
16
+ * src/client, so this half holds its own copy and the parity test pins both.
17
+ */
18
+ import type { SettingsDocHandle } from './compat.js';
19
+ /** The native handle's snapshot shape — the bridge payload cast at the boundary. */
20
+ type DocSnapshot = ReturnType<SettingsDocHandle['getSnapshot']>;
21
+ export declare class BridgeDocHandle implements SettingsDocHandle {
22
+ private snapshot;
23
+ private listeners;
24
+ private revision;
25
+ private inflight;
26
+ private readonly routes;
27
+ constructor(ns: string);
28
+ /** The bridge transport is shape-agnostic; the ns payload narrows at this boundary. */
29
+ getSnapshot(): DocSnapshot;
30
+ subscribe(listener: () => void): () => void;
31
+ set(field: string, value: unknown): Promise<void>;
32
+ private notify;
33
+ private request;
34
+ private refresh;
35
+ private mutate;
36
+ }
37
+ export {};
38
+ //# sourceMappingURL=bridge-scope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge-scope.d.ts","sourceRoot":"","sources":["../../../src/client/bridge-scope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAOpD,oFAAoF;AACpF,KAAK,WAAW,GAAG,UAAU,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAAC,CAAA;AAM/D,qBAAa,eAAgB,YAAW,iBAAiB;IACvD,OAAO,CAAC,QAAQ,CAAoE;IACpF,OAAO,CAAC,SAAS,CAAwB;IACzC,OAAO,CAAC,QAAQ,CAAoB;IACpC,OAAO,CAAC,QAAQ,CAA2B;IAC3C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsC;gBAEjD,EAAE,EAAE,MAAM;IAKtB,uFAAuF;IACvF,WAAW,IAAI,WAAW;IAI1B,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAKrC,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvD,OAAO,CAAC,MAAM;YAIA,OAAO;YAUP,OAAO;YAsBP,MAAM;CAarB"}
@@ -0,0 +1,81 @@
1
+ /** Must match src/bridge.ts bridgeRoutesFor character for character. */
2
+ function bridgeRoutesFor(ns) {
3
+ return { describe: `/api/${ns}/settings/describe`, mutate: `/api/${ns}/settings/mutate` };
4
+ }
5
+ export class BridgeDocHandle {
6
+ snapshot = { status: 'pending', value: undefined, writable: true };
7
+ listeners = new Set();
8
+ revision;
9
+ inflight;
10
+ routes;
11
+ constructor(ns) {
12
+ this.routes = bridgeRoutesFor(ns);
13
+ void this.refresh();
14
+ }
15
+ /** The bridge transport is shape-agnostic; the ns payload narrows at this boundary. */
16
+ getSnapshot() {
17
+ return this.snapshot;
18
+ }
19
+ subscribe(listener) {
20
+ this.listeners.add(listener);
21
+ return () => { this.listeners.delete(listener); };
22
+ }
23
+ async set(field, value) {
24
+ await this.mutate([{ op: 'set', path: [field], value }]);
25
+ }
26
+ notify() {
27
+ for (const l of [...this.listeners])
28
+ l();
29
+ }
30
+ async request(path, body) {
31
+ const response = await fetch(path, {
32
+ method: 'POST',
33
+ headers: { 'content-type': 'application/json' },
34
+ body: JSON.stringify(body ?? {}),
35
+ });
36
+ if (!response.ok)
37
+ throw new Error(`bridge ${path} HTTP ${response.status}`);
38
+ return await response.json();
39
+ }
40
+ async refresh() {
41
+ if (this.inflight !== undefined)
42
+ return this.inflight;
43
+ this.inflight = (async () => {
44
+ try {
45
+ const body = await this.request(this.routes.describe);
46
+ if (body.ok && body.value?.descriptor !== undefined) {
47
+ const d = body.value.descriptor;
48
+ this.revision = typeof d.revision === 'number' ? d.revision : undefined;
49
+ this.snapshot = { status: 'ready', value: d.value, writable: body.value.writable !== false };
50
+ }
51
+ else {
52
+ this.snapshot = { status: 'error', value: undefined, writable: false };
53
+ }
54
+ }
55
+ catch {
56
+ this.snapshot = { status: 'error', value: undefined, writable: false };
57
+ }
58
+ finally {
59
+ this.inflight = undefined;
60
+ }
61
+ this.notify();
62
+ })();
63
+ return this.inflight;
64
+ }
65
+ async mutate(ops) {
66
+ const body = await this.request(this.routes.mutate, { ops, expectedRevision: this.revision });
67
+ if (body.ok && body.value?.descriptor !== undefined) {
68
+ const d = body.value.descriptor;
69
+ this.revision = typeof d.revision === 'number' ? d.revision : undefined;
70
+ this.snapshot = { status: 'ready', value: d.value, writable: this.snapshot.writable };
71
+ }
72
+ else if (body.code === 'settings-conflict') {
73
+ await this.refresh(); // optimistic concurrency lost: pull the authoritative value so the next write carries a fresh revision
74
+ }
75
+ else {
76
+ throw new Error(`bridge mutate failed: ${body.code ?? 'unknown'} ${body.message ?? ''}`);
77
+ }
78
+ this.notify();
79
+ }
80
+ }
81
+ //# sourceMappingURL=bridge-scope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge-scope.js","sourceRoot":"","sources":["../../../src/client/bridge-scope.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * compat.ts —— 版本敏感代码的**唯一窄腰**(INDEX §C:版本差异代码只许出现在
3
+ * 窄腰文件,能力探测优先,禁止读宿主版本号)。
4
+ *
5
+ * 本插件已核实的两处分叉(findings §1.1 #5 / 迁移执行期补勘):
6
+ * 1. 持久化设置面:0.1.7+ 走 `configForms.get(ns)`;≤0.1.5 走
7
+ * `settingsScope.bind({ namespace })`。0.1.7-rc.1 的 client-ui-settings 包
8
+ * 已不含 `settingsScope` 字样(2026-10-04 node_modules 全文核查)——两服务
9
+ * 按代互斥,双 scoped-inject 天然不会双触发。
10
+ * 2. 草稿回填:≤0.1.5 在 `input.for(actx).actions.setDraft`,0.1.7+ 直挂
11
+ * `.setDraft`(compat/0.1.5:src/client/index.ts vs 本分支同文件)。
12
+ *
13
+ * 缺席服务上的 scoped-inject fiber 永久 PENDING:与 `dsh-family.tab` 在持有者
14
+ * (跨插件族,非宿主本体)缺席时的惰性等待同型,不阻塞插件其余半区——
15
+ * 插件级 inject 清单因此**只含六线通用服务**,防整插件 PENDING 静默失活。
16
+ *
17
+ * All @deepseek-ai/* imports are type-only (client bundle purity).
18
+ */
19
+ import type { Context as ClientContext } from '@deepseek-ai/cordis';
20
+ /**
21
+ * Structural minimum of a durable settings document handle — shared by
22
+ * `configForms.get()` (0.1.7+) and `settingsScope.bind()` (≤0.1.5). Declared
23
+ * locally (NOT as ambient augmentation of `@deepseek-ai/dsh-client-ui-settings/client`)
24
+ * so the compile face stays identical against every host line's real types.
25
+ */
26
+ export interface SettingsDocHandle {
27
+ getSnapshot(): {
28
+ status: string;
29
+ value: {
30
+ busyEnter?: string;
31
+ } | undefined;
32
+ writable: boolean;
33
+ };
34
+ subscribe(listener: () => void): () => void;
35
+ set(field: string, value: unknown): Promise<void>;
36
+ }
37
+ /** Anything registerSettingsFaces needs beyond the pin itself. */
38
+ export interface SettingsFacesDeps {
39
+ /** Durable namespace holding the pinned field (`ui-conversation`). */
40
+ namespace: string;
41
+ /** Field to pin (busy-Enter takeover). */
42
+ field: string;
43
+ /** Value to pin. */
44
+ value: unknown;
45
+ /** Called once a settings face resolves; receives the scope handle (the
46
+ * family tab card reads it). Never called on hosts with neither service. */
47
+ onScope: (scope: SettingsDocHandle) => void;
48
+ }
49
+ /**
50
+ * Pin the busy-Enter field through whichever durable-settings service this
51
+ * host line carries, then hand the resolved scope to `onScope`.
52
+ *
53
+ * Both variants are scoped sub-injects: on a host without the service the
54
+ * fiber waits forever WITHOUT blocking the plugin's other faces (same posture
55
+ * as the family tab's slot-inject when the family holder is absent).
56
+ */
57
+ export declare function registerSettingsFaces(ctx: ClientContext, deps: SettingsFacesDeps): void;
58
+ /**
59
+ * Draft back-fill normalized across host lines: prefers the direct
60
+ * `.setDraft` (0.1.7+), falls back to the `.actions` parking spot (≤0.1.5).
61
+ * Pure shape probing on the conversation row object — no version reads.
62
+ */
63
+ export declare function draftWriter(conversation: {
64
+ input: {
65
+ for(actx: unknown): unknown;
66
+ };
67
+ }, actx: unknown): (text: string) => void;
68
+ //# sourceMappingURL=compat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compat.d.ts","sourceRoot":"","sources":["../../../src/client/compat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAEnE;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,WAAW,IAAI;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE;YAAE,SAAS,CAAC,EAAE,MAAM,CAAA;SAAE,GAAG,SAAS,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAA;IAC/F,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAA;IAC3C,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAClD;AAED,kEAAkE;AAClE,MAAM,WAAW,iBAAiB;IAChC,sEAAsE;IACtE,SAAS,EAAE,MAAM,CAAA;IACjB,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAA;IACb,oBAAoB;IACpB,KAAK,EAAE,OAAO,CAAA;IACd;gFAC4E;IAC5E,OAAO,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAA;CAC5C;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAyBvF;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,YAAY,EAAE;IAAE,KAAK,EAAE;QAAE,GAAG,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAA;KAAE,CAAA;CAAE,EACxD,IAAI,EAAE,OAAO,GACZ,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CASxB"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Pin the busy-Enter field through whichever durable-settings service this
3
+ * host line carries, then hand the resolved scope to `onScope`.
4
+ *
5
+ * Both variants are scoped sub-injects: on a host without the service the
6
+ * fiber waits forever WITHOUT blocking the plugin's other faces (same posture
7
+ * as the family tab's slot-inject when the family holder is absent).
8
+ */
9
+ export function registerSettingsFaces(ctx, deps) {
10
+ // cordis inject 回调收到的是 (ctx, config)——服务要按名从 scope 对象上读
11
+ // (thinking-levels 腰的同款形态;0.7.1 曾把参数当裸服务 .get/.bind 调用,
12
+ // 每一代宿主上都是 TypeError,纤维暗死 → onScope 永不回调 → 卡永远降级)。
13
+ const scopeInject = ctx.inject;
14
+ // Modern hosts (0.1.7+): configForms owns cross-entry durable writes.
15
+ scopeInject(['configForms'], (scope) => {
16
+ const forms = scope.configForms;
17
+ if (forms === undefined)
18
+ return;
19
+ const handle = forms.get(deps.namespace);
20
+ void handle.set(deps.field, deps.value);
21
+ deps.onScope(handle);
22
+ });
23
+ // Old hosts (≤0.1.5): namespaced durable scope via bind().
24
+ scopeInject(['settingsScope'], (scope) => {
25
+ const settingsScope = scope.settingsScope;
26
+ if (settingsScope === undefined)
27
+ return;
28
+ const handle = settingsScope.bind({ namespace: deps.namespace });
29
+ void handle.set(deps.field, deps.value);
30
+ deps.onScope(handle);
31
+ });
32
+ }
33
+ /**
34
+ * Draft back-fill normalized across host lines: prefers the direct
35
+ * `.setDraft` (0.1.7+), falls back to the `.actions` parking spot (≤0.1.5).
36
+ * Pure shape probing on the conversation row object — no version reads.
37
+ */
38
+ export function draftWriter(conversation, actx) {
39
+ return (text) => {
40
+ const row = conversation.input.for(actx);
41
+ if (typeof row.setDraft === 'function')
42
+ row.setDraft(text);
43
+ else
44
+ row.actions?.setDraft(text);
45
+ };
46
+ }
47
+ //# sourceMappingURL=compat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compat.js","sourceRoot":"","sources":["../../../src/client/compat.ts"],"names":[],"mappings":"AA6CA;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAkB,EAAE,IAAuB;IAC/E,wDAAwD;IACxD,wDAAwD;IACxD,mDAAmD;IACnD,MAAM,WAAW,GAAI,GAEnB,CAAC,MAAM,CAAA;IACT,sEAAsE;IACtE,WAAW,CAAC,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE;QACrC,MAAM,KAAK,GAAG,KAAK,CAAC,WAAwE,CAAA;QAC5F,IAAI,KAAK,KAAK,SAAS;YAAE,OAAM;QAC/B,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QACxC,KAAK,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAA;QACvC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;IACtB,CAAC,CAAC,CAAA;IACF,2DAA2D;IAC3D,WAAW,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE;QACvC,MAAM,aAAa,GAAG,KAAK,CAAC,aAEf,CAAA;QACb,IAAI,aAAa,KAAK,SAAS;YAAE,OAAM;QACvC,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAA;QAChE,KAAK,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAA;QACvC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;IACtB,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CACzB,YAAwD,EACxD,IAAa;IAEb,OAAO,CAAC,IAAY,EAAE,EAAE;QACtB,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAGtC,CAAA;QACD,IAAI,OAAO,GAAG,CAAC,QAAQ,KAAK,UAAU;YAAE,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;;YACrD,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAA;IAClC,CAAC,CAAA;AACH,CAAC"}
@@ -22,7 +22,8 @@ export interface FamilyCardScope {
22
22
  subscribe(listener: () => void): () => void;
23
23
  }
24
24
  export interface FamilyCardProps {
25
- scope: FamilyCardScope;
25
+ /** 活引用:≤0.1.5 settingsScope 永不 resolve 时保持 undefined(降级渲染)。 */
26
+ scope?: FamilyCardScope;
26
27
  t?: (key: string, params?: Record<string, unknown>) => string;
27
28
  }
28
29
  export declare function InputTrafficFamilyCard({ scope, t }: FamilyCardProps): JSX.Element;