@zhin.js/host-http 1.0.5 → 1.0.6

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.
@@ -2,6 +2,20 @@ import type { AuthScope } from './token-registry.js';
2
2
  import type { DatabaseHostConsole } from '@zhin.js/plugin-runtime';
3
3
  import { type ConsoleEndpointSummary } from '@zhin.js/console-protocol';
4
4
  import { type ConsoleRpcExtendedCtx } from './console-rpc-extended.js';
5
+ /**
6
+ * Console RPC 请求结构:未锚定 endpoint 的会话地址(结构对齐
7
+ * `Omit<ConversationRef,'endpoint'>`;host/http 架构分层不允许依赖
8
+ * `@zhin.js/im-contract`,故本地结构化声明,endpoint 由 ImRuntime 锚定)。
9
+ */
10
+ export interface ConversationAddress {
11
+ readonly kind: 'private' | 'group' | 'channel';
12
+ readonly id: string;
13
+ readonly parent?: Readonly<{
14
+ readonly kind: 'group' | 'channel';
15
+ readonly id: string;
16
+ }>;
17
+ readonly threadId?: string;
18
+ }
5
19
  export type RuntimeConsoleRpcMessage = {
6
20
  readonly type?: unknown;
7
21
  readonly requestId?: unknown;
@@ -83,14 +97,8 @@ export type RuntimeDatabaseInfo = {
83
97
  export type RuntimeEndpointSendInput = {
84
98
  readonly adapter: string;
85
99
  readonly endpointId: string;
86
- readonly channelId: string;
87
- readonly channelType: string;
100
+ readonly conversation: ConversationAddress;
88
101
  readonly content: unknown;
89
- readonly parent?: {
90
- type?: string;
91
- id?: string;
92
- name?: string;
93
- };
94
102
  };
95
103
  export declare function pickRpcReply(message: RuntimeConsoleRpcMessage, payloads: readonly RuntimeConsoleRpcReply[]): RuntimeConsoleRpcReply | null;
96
104
  export declare function dispatchRuntimeConsoleRpc(message: RuntimeConsoleRpcMessage, ctx: RuntimeConsoleRpcContext): Promise<RuntimeConsoleRpcReply[]>;
@@ -1,5 +1,22 @@
1
1
  import { assertDemoConsoleRpcAllowed, endpointSendResult, normalizeConsoleRpcMessage, } from '@zhin.js/console-protocol';
2
2
  import { dispatchExtendedConsoleRpc } from './console-rpc-extended.js';
3
+ /** `$channel_type`/`$channel_id`/`$parent` wire 字段 → 会话地址(RPC 边界组帧)。 */
4
+ function wireConversation(channelType, channelId, parent) {
5
+ // console 旧 wire 允许 channel_id 自带场景前缀(`group:123`),解析结果优先
6
+ const prefixed = /^(private|group|channel|direct|c2c|temp):(.+)$/iu.exec(channelId);
7
+ const rawKind = channelType || prefixed?.[1] || 'private';
8
+ const kind = rawKind === 'group' || rawKind === 'channel' ? rawKind : 'private';
9
+ const wire = parent && typeof parent === 'object'
10
+ ? parent
11
+ : undefined;
12
+ const parentKind = wire?.type === 'group' || wire?.type === 'channel' ? wire.type : undefined;
13
+ const parentId = typeof wire?.id === 'string' && wire.id ? wire.id : undefined;
14
+ return {
15
+ kind,
16
+ id: prefixed ? prefixed[2] : channelId,
17
+ ...(parentKind && parentId ? { parent: { kind: parentKind, id: parentId } } : {}),
18
+ };
19
+ }
3
20
  export function pickRpcReply(message, payloads) {
4
21
  const requestId = message.requestId;
5
22
  return ((requestId != null ? payloads.find((payload) => payload.requestId === requestId) : undefined)
@@ -557,8 +574,7 @@ export async function dispatchRuntimeConsoleRpc(message, ctx) {
557
574
  const channelId = String(data.$channel_id ?? '');
558
575
  const channelType = String(data.$channel_type ?? '');
559
576
  const content = data.$content;
560
- // channelType is optional: ImRuntime tolerates an empty value and
561
- // targets the bare channel id (parity with the legacy RPC handler).
577
+ // channelType 可省:wireConversation 归一为 private(与旧 RPC 行为对齐)。
562
578
  if (!adapter || !endpointId || !channelId || content === undefined) {
563
579
  emit({
564
580
  requestId,
@@ -573,10 +589,8 @@ export async function dispatchRuntimeConsoleRpc(message, ctx) {
573
589
  const result = await ctx.sendEndpointMessage({
574
590
  adapter,
575
591
  endpointId,
576
- channelId,
577
- channelType,
592
+ conversation: wireConversation(channelType, channelId, data.$parent),
578
593
  content,
579
- parent: data.$parent,
580
594
  });
581
595
  // Legacy contract: { message_id }. Keep messageId for new callers.
582
596
  emit({ requestId, data: endpointSendResult(result.messageId) });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/host-http",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "Minimal HTTP and WebSocket host for Plugin Runtime (no Koa)",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -21,7 +21,7 @@
21
21
  "@zhin.js/console-protocol": "1.1.0",
22
22
  "@zhin.js/host-http-contract": "1.0.0",
23
23
  "@zhin.js/logger": "1.0.75",
24
- "@zhin.js/plugin-runtime": "1.1.2"
24
+ "@zhin.js/plugin-runtime": "1.1.3"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@types/node": "^26.1.2",
@@ -8,6 +8,44 @@ import {
8
8
  } from '@zhin.js/console-protocol';
9
9
  import { dispatchExtendedConsoleRpc, type ConsoleRpcExtendedCtx } from './console-rpc-extended.js';
10
10
 
11
+ /**
12
+ * Console RPC 请求结构:未锚定 endpoint 的会话地址(结构对齐
13
+ * `Omit<ConversationRef,'endpoint'>`;host/http 架构分层不允许依赖
14
+ * `@zhin.js/im-contract`,故本地结构化声明,endpoint 由 ImRuntime 锚定)。
15
+ */
16
+ export interface ConversationAddress {
17
+ readonly kind: 'private' | 'group' | 'channel';
18
+ readonly id: string;
19
+ readonly parent?: Readonly<{
20
+ readonly kind: 'group' | 'channel';
21
+ readonly id: string;
22
+ }>;
23
+ readonly threadId?: string;
24
+ }
25
+
26
+ /** `$channel_type`/`$channel_id`/`$parent` wire 字段 → 会话地址(RPC 边界组帧)。 */
27
+ function wireConversation(
28
+ channelType: string,
29
+ channelId: string,
30
+ parent: unknown,
31
+ ): ConversationAddress {
32
+ // console 旧 wire 允许 channel_id 自带场景前缀(`group:123`),解析结果优先
33
+ const prefixed = /^(private|group|channel|direct|c2c|temp):(.+)$/iu.exec(channelId);
34
+ const rawKind = channelType || prefixed?.[1] || 'private';
35
+ const kind: ConversationAddress['kind'] =
36
+ rawKind === 'group' || rawKind === 'channel' ? rawKind : 'private';
37
+ const wire = parent && typeof parent === 'object'
38
+ ? parent as { readonly type?: unknown; readonly id?: unknown }
39
+ : undefined;
40
+ const parentKind = wire?.type === 'group' || wire?.type === 'channel' ? wire.type : undefined;
41
+ const parentId = typeof wire?.id === 'string' && wire.id ? wire.id : undefined;
42
+ return {
43
+ kind,
44
+ id: prefixed ? prefixed[2]! : channelId,
45
+ ...(parentKind && parentId ? { parent: { kind: parentKind, id: parentId } } : {}),
46
+ };
47
+ }
48
+
11
49
  export type RuntimeConsoleRpcMessage = {
12
50
  readonly type?: unknown;
13
51
  readonly requestId?: unknown;
@@ -86,10 +124,8 @@ export type RuntimeDatabaseInfo = {
86
124
  export type RuntimeEndpointSendInput = {
87
125
  readonly adapter: string;
88
126
  readonly endpointId: string;
89
- readonly channelId: string;
90
- readonly channelType: string;
127
+ readonly conversation: ConversationAddress;
91
128
  readonly content: unknown;
92
- readonly parent?: { type?: string; id?: string; name?: string };
93
129
  };
94
130
 
95
131
  export function pickRpcReply(
@@ -625,8 +661,7 @@ export async function dispatchRuntimeConsoleRpc(
625
661
  const channelId = String(data.$channel_id ?? '');
626
662
  const channelType = String(data.$channel_type ?? '');
627
663
  const content = data.$content;
628
- // channelType is optional: ImRuntime tolerates an empty value and
629
- // targets the bare channel id (parity with the legacy RPC handler).
664
+ // channelType 可省:wireConversation 归一为 private(与旧 RPC 行为对齐)。
630
665
  if (!adapter || !endpointId || !channelId || content === undefined) {
631
666
  emit({
632
667
  requestId,
@@ -641,11 +676,8 @@ export async function dispatchRuntimeConsoleRpc(
641
676
  const result = await ctx.sendEndpointMessage({
642
677
  adapter,
643
678
  endpointId,
644
- channelId,
645
- channelType,
679
+ conversation: wireConversation(channelType, channelId, data.$parent),
646
680
  content,
647
- parent: data.$parent as
648
- { type?: string; id?: string; name?: string } | undefined,
649
681
  });
650
682
  // Legacy contract: { message_id }. Keep messageId for new callers.
651
683
  emit({ requestId, data: endpointSendResult(result.messageId) });