@yu_robotics/remote-cli-router 1.0.1 → 1.0.4

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.
@@ -1,8 +1,9 @@
1
- import { BindingCode, UserBinding } from '../types';
1
+ import { DeviceBinding, UserBinding } from '../types';
2
2
  import { JsonStore } from '../storage/JsonStore';
3
3
  /**
4
4
  * Binding Manager
5
5
  * Responsible for managing user and device binding relationships
6
+ * Supports multiple devices per user with one active device
6
7
  */
7
8
  export declare class BindingManager {
8
9
  private store;
@@ -13,45 +14,56 @@ export declare class BindingManager {
13
14
  * @param deviceName Device name
14
15
  * @returns Binding code object
15
16
  */
16
- generateBindingCode(deviceId: string, deviceName: string): Promise<BindingCode>;
17
+ generateBindingCode(deviceId: string, deviceName: string): Promise<import('../types').BindingCode>;
17
18
  /**
18
19
  * Verify binding code
19
20
  * @param code Binding code
20
21
  * @returns Binding code object, returns null if invalid or expired
21
22
  */
22
- verifyBindingCode(code: string): Promise<BindingCode | null>;
23
+ verifyBindingCode(code: string): Promise<import('../types').BindingCode | null>;
23
24
  /**
24
- * Bind user and device
25
- * @param openId Feishu user open_id
26
- * @param deviceId Device unique identifier
27
- * @param deviceName Device name
25
+ * Bind user and device (supports multi-device)
26
+ * First device becomes active; subsequent devices are added as inactive.
28
27
  */
29
28
  bindUser(openId: string, deviceId: string, deviceName: string): Promise<void>;
30
29
  /**
31
30
  * Get user binding information
32
- * @param openId Feishu user open_id
33
- * @returns Binding information, returns null if not bound
34
31
  */
35
32
  getUserBinding(openId: string): Promise<UserBinding | null>;
36
33
  /**
37
- * Get device binding information
38
- * @param deviceId Device unique identifier
39
- * @returns Binding information, returns null if not bound
34
+ * Get all devices for a user
35
+ */
36
+ getUserDevices(openId: string): Promise<DeviceBinding[]>;
37
+ /**
38
+ * Get the active device for a user
39
+ */
40
+ getActiveDevice(openId: string): Promise<DeviceBinding | null>;
41
+ /**
42
+ * Switch the active device for a user
43
+ * @returns true if switch was successful
44
+ */
45
+ switchActiveDevice(openId: string, deviceId: string): Promise<boolean>;
46
+ /**
47
+ * Unbind a specific device from a user
48
+ * If the active device is removed, promotes the first remaining device.
49
+ * If no devices remain, removes the entire user binding.
50
+ * @returns true if device was found and removed
51
+ */
52
+ unbindDevice(openId: string, deviceId: string): Promise<boolean>;
53
+ /**
54
+ * Get device binding information via reverse lookup
40
55
  */
41
56
  getDeviceBinding(deviceId: string): Promise<UserBinding | null>;
42
57
  /**
43
- * Unbind user
44
- * @param openId Feishu user open_id
58
+ * Unbind all devices for a user
45
59
  */
46
60
  unbindUser(openId: string): Promise<void>;
47
61
  /**
48
62
  * Update user last active time
49
- * @param openId Feishu user open_id
50
63
  */
51
64
  updateLastActive(openId: string): Promise<void>;
52
65
  /**
53
66
  * Generate random binding code (format: XXX-XXX-XXX)
54
- * @returns Binding code string
55
67
  */
56
68
  private generateRandomCode;
57
69
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"BindingManager.d.ts","sourceRoot":"","sources":["../../src/binding/BindingManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAY;gBAEb,KAAK,EAAE,SAAS;IAI5B;;;;;OAKG;IACG,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAiBrF;;;;OAIG;IACG,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAIlE;;;;;OAKG;IACG,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBnF;;;;OAIG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAIjE;;;;OAIG;IACG,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAIrE;;;OAGG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/C;;;OAGG;IACG,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrD;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAe1B;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
1
+ {"version":3,"file":"BindingManager.d.ts","sourceRoot":"","sources":["../../src/binding/BindingManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD;;;;GAIG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAY;gBAEb,KAAK,EAAE,SAAS;IAI5B;;;;;OAKG;IACG,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,UAAU,EAAE,WAAW,CAAC;IAiBxG;;;;OAIG;IACG,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,UAAU,EAAE,WAAW,GAAG,IAAI,CAAC;IAIrF;;;OAGG;IACG,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA6CnF;;OAEG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAIjE;;OAEG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAK9D;;OAEG;IACG,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAQpE;;;OAGG;IACG,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAsB5E;;;;;OAKG;IACG,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAgCtE;;OAEG;IACG,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAQrE;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/C;;OAEG;IACG,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrD;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAe1B;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
@@ -4,6 +4,7 @@ exports.BindingManager = void 0;
4
4
  /**
5
5
  * Binding Manager
6
6
  * Responsible for managing user and device binding relationships
7
+ * Supports multiple devices per user with one active device
7
8
  */
8
9
  class BindingManager {
9
10
  store;
@@ -39,62 +40,152 @@ class BindingManager {
39
40
  return this.store.getBindingCode(code);
40
41
  }
41
42
  /**
42
- * Bind user and device
43
- * @param openId Feishu user open_id
44
- * @param deviceId Device unique identifier
45
- * @param deviceName Device name
43
+ * Bind user and device (supports multi-device)
44
+ * First device becomes active; subsequent devices are added as inactive.
46
45
  */
47
46
  async bindUser(openId, deviceId, deviceName) {
48
47
  const now = Date.now();
49
- // Check if user already has a binding
50
48
  const existingBinding = await this.getUserBinding(openId);
51
49
  if (existingBinding) {
52
- // Will be overwritten by setUserBinding
50
+ // Check if device already exists (rebinding scenario)
51
+ const deviceIndex = existingBinding.devices.findIndex(d => d.deviceId === deviceId);
52
+ if (deviceIndex >= 0) {
53
+ // Update existing device entry
54
+ existingBinding.devices[deviceIndex].deviceName = deviceName;
55
+ existingBinding.devices[deviceIndex].lastActiveAt = now;
56
+ }
57
+ else {
58
+ // Add new device as inactive
59
+ existingBinding.devices.push({
60
+ deviceId,
61
+ deviceName,
62
+ boundAt: now,
63
+ lastActiveAt: now,
64
+ isActive: false,
65
+ });
66
+ }
67
+ existingBinding.updatedAt = now;
68
+ await this.store.setUserBinding(openId, existingBinding);
69
+ }
70
+ else {
71
+ // First device for this user - set as active
72
+ const binding = {
73
+ openId,
74
+ devices: [{
75
+ deviceId,
76
+ deviceName,
77
+ boundAt: now,
78
+ lastActiveAt: now,
79
+ isActive: true,
80
+ }],
81
+ activeDeviceId: deviceId,
82
+ createdAt: now,
83
+ updatedAt: now,
84
+ };
85
+ await this.store.setUserBinding(openId, binding);
53
86
  }
54
- // Create new binding relationship
55
- const binding = {
56
- openId,
57
- deviceId,
58
- deviceName,
59
- boundAt: now,
60
- lastActiveAt: now
61
- };
62
- // Store user -> device mapping
63
- await this.store.setUserBinding(openId, binding);
64
87
  }
65
88
  /**
66
89
  * Get user binding information
67
- * @param openId Feishu user open_id
68
- * @returns Binding information, returns null if not bound
69
90
  */
70
91
  async getUserBinding(openId) {
71
92
  return this.store.getUserBinding(openId);
72
93
  }
73
94
  /**
74
- * Get device binding information
75
- * @param deviceId Device unique identifier
76
- * @returns Binding information, returns null if not bound
95
+ * Get all devices for a user
96
+ */
97
+ async getUserDevices(openId) {
98
+ const binding = this.store.getUserBinding(openId);
99
+ return binding?.devices || [];
100
+ }
101
+ /**
102
+ * Get the active device for a user
103
+ */
104
+ async getActiveDevice(openId) {
105
+ const binding = this.store.getUserBinding(openId);
106
+ if (!binding || !binding.activeDeviceId) {
107
+ return null;
108
+ }
109
+ return binding.devices.find(d => d.deviceId === binding.activeDeviceId) || null;
110
+ }
111
+ /**
112
+ * Switch the active device for a user
113
+ * @returns true if switch was successful
114
+ */
115
+ async switchActiveDevice(openId, deviceId) {
116
+ const binding = this.store.getUserBinding(openId);
117
+ if (!binding) {
118
+ return false;
119
+ }
120
+ const targetDevice = binding.devices.find(d => d.deviceId === deviceId);
121
+ if (!targetDevice) {
122
+ return false;
123
+ }
124
+ // Update isActive flags
125
+ for (const device of binding.devices) {
126
+ device.isActive = device.deviceId === deviceId;
127
+ }
128
+ binding.activeDeviceId = deviceId;
129
+ binding.updatedAt = Date.now();
130
+ await this.store.setUserBinding(openId, binding);
131
+ return true;
132
+ }
133
+ /**
134
+ * Unbind a specific device from a user
135
+ * If the active device is removed, promotes the first remaining device.
136
+ * If no devices remain, removes the entire user binding.
137
+ * @returns true if device was found and removed
138
+ */
139
+ async unbindDevice(openId, deviceId) {
140
+ const binding = this.store.getUserBinding(openId);
141
+ if (!binding) {
142
+ return false;
143
+ }
144
+ const deviceIndex = binding.devices.findIndex(d => d.deviceId === deviceId);
145
+ if (deviceIndex < 0) {
146
+ return false;
147
+ }
148
+ // Remove device
149
+ binding.devices.splice(deviceIndex, 1);
150
+ await this.store.removeDeviceToUserMap(deviceId);
151
+ if (binding.devices.length === 0) {
152
+ // No devices left, delete the entire binding
153
+ await this.store.deleteUserBinding(openId);
154
+ return true;
155
+ }
156
+ // If the removed device was the active one, promote first remaining device
157
+ if (binding.activeDeviceId === deviceId) {
158
+ binding.devices[0].isActive = true;
159
+ binding.activeDeviceId = binding.devices[0].deviceId;
160
+ }
161
+ binding.updatedAt = Date.now();
162
+ await this.store.setUserBinding(openId, binding);
163
+ return true;
164
+ }
165
+ /**
166
+ * Get device binding information via reverse lookup
77
167
  */
78
168
  async getDeviceBinding(deviceId) {
79
- return this.store.getDeviceBinding(deviceId);
169
+ const openId = this.store.getUserByDeviceId(deviceId);
170
+ if (!openId) {
171
+ return null;
172
+ }
173
+ return this.store.getUserBinding(openId);
80
174
  }
81
175
  /**
82
- * Unbind user
83
- * @param openId Feishu user open_id
176
+ * Unbind all devices for a user
84
177
  */
85
178
  async unbindUser(openId) {
86
179
  await this.store.deleteUserBinding(openId);
87
180
  }
88
181
  /**
89
182
  * Update user last active time
90
- * @param openId Feishu user open_id
91
183
  */
92
184
  async updateLastActive(openId) {
93
185
  await this.store.updateLastActive(openId);
94
186
  }
95
187
  /**
96
188
  * Generate random binding code (format: XXX-XXX-XXX)
97
- * @returns Binding code string
98
189
  */
99
190
  generateRandomCode() {
100
191
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
@@ -1 +1 @@
1
- {"version":3,"file":"BindingManager.js","sourceRoot":"","sources":["../../src/binding/BindingManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"BindingManager.js","sourceRoot":"","sources":["../../src/binding/BindingManager.ts"],"names":[],"mappings":"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"}
@@ -21,6 +21,9 @@ export declare class FeishuLongConnHandler {
21
21
  private appId;
22
22
  private appSecret;
23
23
  private readonly FEISHU_MESSAGE_LIMIT;
24
+ private readonly CARD_ELEMENT_LIMIT;
25
+ private readonly CARD_DATA_SIZE_LIMIT;
26
+ private readonly CARD_SIZE_BUFFER;
24
27
  private messageChains;
25
28
  private lastProcessedLengths;
26
29
  private messageLocks;
@@ -70,8 +73,38 @@ export declare class FeishuLongConnHandler {
70
73
  private handleStatusCommand;
71
74
  /**
72
75
  * Handle unbind command
76
+ * Usage: /unbind or /unbind all (unbind all devices)
77
+ * For unbinding specific device, use /device unbind <device-id>
73
78
  */
74
79
  private handleUnbindCommand;
80
+ /**
81
+ * Handle device command
82
+ * Usage:
83
+ * /device - List all bound devices (same as /device list)
84
+ * /device list - List all bound devices
85
+ * /device switch <device-id|index> - Switch active device (by ID or index number)
86
+ * /device <device-id|index> - Quick switch to device (by ID or index number)
87
+ * /device unbind <device-id|index> - Unbind a specific device (by ID or index number)
88
+ */
89
+ private handleDeviceCommand;
90
+ /**
91
+ * Handle /device list
92
+ */
93
+ private handleDeviceList;
94
+ /**
95
+ * Resolve device identifier (ID or index) to device ID
96
+ * @returns Resolved device ID or null if not found
97
+ */
98
+ private resolveDeviceIdentifier;
99
+ /**
100
+ * Handle /device switch <device-id-or-index>
101
+ * Also handles quick switch: /device <device-id-or-index>
102
+ */
103
+ private handleDeviceSwitch;
104
+ /**
105
+ * Handle /device unbind <device-id-or-index>
106
+ */
107
+ private handleDeviceUnbind;
75
108
  /**
76
109
  * Handle help command
77
110
  */
@@ -107,6 +140,46 @@ export declare class FeishuLongConnHandler {
107
140
  * - "~⬅️ Continued from previous message...~" (44 chars) at start of continuation chunks
108
141
  */
109
142
  private splitTextIntoChunks;
143
+ /**
144
+ * Split Card 2.0 elements into chunks based on Feishu limits
145
+ *
146
+ * Feishu Card 2.0 has two main limits:
147
+ * 1. Element count: Max 200 tagged nodes per card (we use 150 for safety)
148
+ * 2. Data size: Max 3,000,000 characters in the data field (JSON.stringify result)
149
+ *
150
+ * This function splits elements array into chunks that satisfy both limits,
151
+ * and adds continuation indicators between chunks for better UX.
152
+ *
153
+ * Note: Element counting uses recursive tag counting - all nodes with 'tag' property
154
+ * are counted, including nested components, text elements, and container children.
155
+ *
156
+ * @param elements Array of Feishu Card 2.0 elements
157
+ * @returns Array of element chunks, each satisfying Feishu's limits
158
+ */
159
+ private splitElementsIntoChunks;
160
+ /**
161
+ * Recursively count all nodes with 'tag' property in the element tree
162
+ * According to Feishu docs, all nodes with 'tag' property count towards the 200 limit
163
+ *
164
+ * @param obj The object or array to count tags in
165
+ * @returns Total count of nodes with 'tag' property
166
+ */
167
+ private countTaggedNodes;
168
+ /**
169
+ * Check if elements array needs to be split based on Feishu limits
170
+ * @param elements Array of elements to check
171
+ * @returns true if splitting is needed
172
+ */
173
+ private checkIfElementsNeedSplitting;
174
+ /**
175
+ * Create a continuation card message
176
+ * Used when elements need to be split across multiple cards
177
+ *
178
+ * @param openId User's open_id to send the message to
179
+ * @param elements Array of Feishu Card 2.0 elements
180
+ * @returns The new message ID, or null on error
181
+ */
182
+ private createContinuationCard;
110
183
  /**
111
184
  * Update streaming message content
112
185
  * Automatically creates new messages if content exceeds Feishu's size limit
@@ -131,7 +204,7 @@ export declare class FeishuLongConnHandler {
131
204
  * @param sessionAbbr Optional session abbreviation
132
205
  * @param openId User's open_id for creating continuation messages
133
206
  */
134
- finalizeStreamingMessage(messageId: string, elements: any[], sessionAbbr?: string, openId?: string): Promise<boolean>;
207
+ finalizeStreamingMessage(messageId: string, elements: any[], sessionAbbr?: string, openId?: string, cwd?: string): Promise<boolean>;
135
208
  private _finalizeStreamingMessage;
136
209
  /**
137
210
  * Start the Feishu WebSocket long connection
@@ -1 +1 @@
1
- {"version":3,"file":"FeishuLongConnHandler.d.ts","sourceRoot":"","sources":["../../src/feishu/FeishuLongConnHandler.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAE3D,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,SAAS,CAAC;CAClB;AAED;;;GAGG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,QAAQ,CAA8B;IAC9C,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,SAAS,CAAS;IAE1B,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAQ;IAE7C,OAAO,CAAC,aAAa,CAAoC;IAGzD,OAAO,CAAC,oBAAoB,CAAkC;IAE9D,OAAO,CAAC,YAAY,CAAwC;IAE5D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAoB;IACrD,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAY;gBAEvC,MAAM,EAAE,2BAA2B;IAc/C;;OAEG;IACH,gBAAgB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI;IAI1C;;OAEG;IACH,OAAO,CAAC,gBAAgB,CAAC,CAAgG;IAEzH;;OAEG;IACH,mBAAmB,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAIlI;;OAEG;YACW,kBAAkB;IA6BhC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAS3B;;OAEG;IACH,OAAO,CAAC,SAAS;IAIjB;;OAEG;YACW,aAAa;IAgC3B;;;OAGG;YACW,6BAA6B;IA+D3C;;OAEG;YACW,iBAAiB;IAuB/B;;OAEG;YACW,mBAAmB;IAuBjC;;OAEG;YACW,mBAAmB;IAmBjC;;OAEG;YACW,iBAAiB;IAmB/B;;OAEG;YACW,oBAAoB;IA6DlC;;OAEG;YACW,cAAc;IAc5B;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAiBjE;;;OAGG;IACG,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,GAAE,MAAyB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IA4BxG;;;OAGG;YACW,eAAe;IAc7B;;;;;;;OAOG;IACH,OAAO,CAAC,mBAAmB;IAwC3B;;;;;;;;;;;;OAYG;IACG,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;YAIrF,uBAAuB;IA8BrC;;;;;;;;OAQG;IACG,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;YAI7G,yBAAyB;IAiDvC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA4B5B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB3B;;OAEG;IACH,iBAAiB,IAAI,cAAc;CAGpC"}
1
+ {"version":3,"file":"FeishuLongConnHandler.d.ts","sourceRoot":"","sources":["../../src/feishu/FeishuLongConnHandler.ts"],"names":[],"mappings":"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"}