@krischoichoi/channel-weixin 0.6.0

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 (138) hide show
  1. package/README.md +101 -0
  2. package/lib/adapter.d.ts +90 -0
  3. package/lib/adapter.d.ts.map +1 -0
  4. package/lib/adapter.js +247 -0
  5. package/lib/adapter.js.map +1 -0
  6. package/lib/auth/account-store.d.ts +60 -0
  7. package/lib/auth/account-store.d.ts.map +1 -0
  8. package/lib/auth/account-store.js +84 -0
  9. package/lib/auth/account-store.js.map +1 -0
  10. package/lib/auth/login.d.ts +83 -0
  11. package/lib/auth/login.d.ts.map +1 -0
  12. package/lib/auth/login.js +202 -0
  13. package/lib/auth/login.js.map +1 -0
  14. package/lib/config.d.ts +52 -0
  15. package/lib/config.d.ts.map +1 -0
  16. package/lib/config.js +36 -0
  17. package/lib/config.js.map +1 -0
  18. package/lib/definition.d.ts +59 -0
  19. package/lib/definition.d.ts.map +1 -0
  20. package/lib/definition.js +146 -0
  21. package/lib/definition.js.map +1 -0
  22. package/lib/ilink/base-info.d.ts +22 -0
  23. package/lib/ilink/base-info.d.ts.map +1 -0
  24. package/lib/ilink/base-info.js +11 -0
  25. package/lib/ilink/base-info.js.map +1 -0
  26. package/lib/ilink/client.d.ts +110 -0
  27. package/lib/ilink/client.d.ts.map +1 -0
  28. package/lib/ilink/client.js +308 -0
  29. package/lib/ilink/client.js.map +1 -0
  30. package/lib/ilink/constants.d.ts +59 -0
  31. package/lib/ilink/constants.d.ts.map +1 -0
  32. package/lib/ilink/constants.js +59 -0
  33. package/lib/ilink/constants.js.map +1 -0
  34. package/lib/ilink/errors.d.ts +79 -0
  35. package/lib/ilink/errors.d.ts.map +1 -0
  36. package/lib/ilink/errors.js +121 -0
  37. package/lib/ilink/errors.js.map +1 -0
  38. package/lib/ilink/headers.d.ts +40 -0
  39. package/lib/ilink/headers.d.ts.map +1 -0
  40. package/lib/ilink/headers.js +70 -0
  41. package/lib/ilink/headers.js.map +1 -0
  42. package/lib/ilink/schema.d.ts +154 -0
  43. package/lib/ilink/schema.d.ts.map +1 -0
  44. package/lib/ilink/schema.js +140 -0
  45. package/lib/ilink/schema.js.map +1 -0
  46. package/lib/ilink/types.d.ts +235 -0
  47. package/lib/ilink/types.d.ts.map +1 -0
  48. package/lib/ilink/types.js +21 -0
  49. package/lib/ilink/types.js.map +1 -0
  50. package/lib/index.d.ts +50 -0
  51. package/lib/index.d.ts.map +1 -0
  52. package/lib/index.js +91 -0
  53. package/lib/index.js.map +1 -0
  54. package/lib/manifest.d.ts +54 -0
  55. package/lib/manifest.d.ts.map +1 -0
  56. package/lib/manifest.js +32 -0
  57. package/lib/manifest.js.map +1 -0
  58. package/lib/media/decrypt.d.ts +3 -0
  59. package/lib/media/decrypt.d.ts.map +1 -0
  60. package/lib/media/decrypt.js +16 -0
  61. package/lib/media/decrypt.js.map +1 -0
  62. package/lib/media/download.d.ts +22 -0
  63. package/lib/media/download.d.ts.map +1 -0
  64. package/lib/media/download.js +62 -0
  65. package/lib/media/download.js.map +1 -0
  66. package/lib/media/encrypt.d.ts +3 -0
  67. package/lib/media/encrypt.d.ts.map +1 -0
  68. package/lib/media/encrypt.js +16 -0
  69. package/lib/media/encrypt.js.map +1 -0
  70. package/lib/media/send-media.d.ts +41 -0
  71. package/lib/media/send-media.d.ts.map +1 -0
  72. package/lib/media/send-media.js +52 -0
  73. package/lib/media/send-media.js.map +1 -0
  74. package/lib/media/silk-transcode.d.ts +38 -0
  75. package/lib/media/silk-transcode.d.ts.map +1 -0
  76. package/lib/media/silk-transcode.js +88 -0
  77. package/lib/media/silk-transcode.js.map +1 -0
  78. package/lib/media/upload.d.ts +38 -0
  79. package/lib/media/upload.d.ts.map +1 -0
  80. package/lib/media/upload.js +122 -0
  81. package/lib/media/upload.js.map +1 -0
  82. package/lib/messaging/dedup.d.ts +87 -0
  83. package/lib/messaging/dedup.d.ts.map +1 -0
  84. package/lib/messaging/dedup.js +127 -0
  85. package/lib/messaging/dedup.js.map +1 -0
  86. package/lib/messaging/mapper.d.ts +26 -0
  87. package/lib/messaging/mapper.d.ts.map +1 -0
  88. package/lib/messaging/mapper.js +107 -0
  89. package/lib/messaging/mapper.js.map +1 -0
  90. package/lib/messaging/monitor.d.ts +109 -0
  91. package/lib/messaging/monitor.d.ts.map +1 -0
  92. package/lib/messaging/monitor.js +234 -0
  93. package/lib/messaging/monitor.js.map +1 -0
  94. package/lib/messaging/quote.d.ts +9 -0
  95. package/lib/messaging/quote.d.ts.map +1 -0
  96. package/lib/messaging/quote.js +35 -0
  97. package/lib/messaging/quote.js.map +1 -0
  98. package/lib/messaging/send.d.ts +54 -0
  99. package/lib/messaging/send.d.ts.map +1 -0
  100. package/lib/messaging/send.js +173 -0
  101. package/lib/messaging/send.js.map +1 -0
  102. package/lib/messaging/typing.d.ts +34 -0
  103. package/lib/messaging/typing.d.ts.map +1 -0
  104. package/lib/messaging/typing.js +56 -0
  105. package/lib/messaging/typing.js.map +1 -0
  106. package/lib/storage/context-token.d.ts +26 -0
  107. package/lib/storage/context-token.d.ts.map +1 -0
  108. package/lib/storage/context-token.js +26 -0
  109. package/lib/storage/context-token.js.map +1 -0
  110. package/lib/storage/sync-cursor.d.ts +27 -0
  111. package/lib/storage/sync-cursor.d.ts.map +1 -0
  112. package/lib/storage/sync-cursor.js +25 -0
  113. package/lib/storage/sync-cursor.js.map +1 -0
  114. package/lib/transport.d.ts +38 -0
  115. package/lib/transport.d.ts.map +1 -0
  116. package/lib/transport.js +68 -0
  117. package/lib/transport.js.map +1 -0
  118. package/lib/upstream/compat.d.ts +54 -0
  119. package/lib/upstream/compat.d.ts.map +1 -0
  120. package/lib/upstream/compat.js +54 -0
  121. package/lib/upstream/compat.js.map +1 -0
  122. package/lib/upstream/config-manager.d.ts +35 -0
  123. package/lib/upstream/config-manager.d.ts.map +1 -0
  124. package/lib/upstream/config-manager.js +91 -0
  125. package/lib/upstream/config-manager.js.map +1 -0
  126. package/lib/upstream/index.d.ts +42 -0
  127. package/lib/upstream/index.d.ts.map +1 -0
  128. package/lib/upstream/index.js +13 -0
  129. package/lib/upstream/index.js.map +1 -0
  130. package/lib/upstream/port.d.ts +153 -0
  131. package/lib/upstream/port.d.ts.map +1 -0
  132. package/lib/upstream/port.js +15 -0
  133. package/lib/upstream/port.js.map +1 -0
  134. package/lib/upstream/tencent-upstream.d.ts +116 -0
  135. package/lib/upstream/tencent-upstream.d.ts.map +1 -0
  136. package/lib/upstream/tencent-upstream.js +518 -0
  137. package/lib/upstream/tencent-upstream.js.map +1 -0
  138. package/package.json +48 -0
@@ -0,0 +1,235 @@
1
+ /**
2
+ * Classification: C — duplicate protocol wire types [@deprecated upstream-gap].
3
+ *
4
+ * iLink message / media / QR wire shapes self-maintained. The official
5
+ * @tencent-weixin/openclaw-weixin has equivalent internal enums and types, but
6
+ * its package is OpenClaw-coupled. These are therefore DSH-side structural
7
+ * mirrors used by the mapper and send paths, kept as an explicit upstream-gap
8
+ * until Tencent exports a host-neutral API.
9
+ */
10
+ /**
11
+ * Tencent Weixin iLink wire types.
12
+ *
13
+ * Ported from the upstream Tencent/openclaw-weixin proto mirror. Bytes fields
14
+ * (context buffer, media AES keys) are base64 strings in JSON.
15
+ */
16
+ import type { ChannelId } from '@krischoichoi/channel-core';
17
+ /** Common request metadata attached to every iLink CGI request. */
18
+ export interface ILinkBaseInfo {
19
+ channel_version?: string;
20
+ /** Self-declared identity of the bot/app, UA-style `Name/Version`. */
21
+ bot_agent?: string;
22
+ }
23
+ /** Enum values for `message_type`. */
24
+ export declare const MESSAGE_TYPE_USER = 1;
25
+ export declare const MESSAGE_TYPE_BOT = 2;
26
+ /** Enum values for `message_state`. */
27
+ export declare const MESSAGE_STATE_NEW = 0;
28
+ export declare const MESSAGE_STATE_GENERATING = 1;
29
+ export declare const MESSAGE_STATE_FINISH = 2;
30
+ /** Enum values for `item_list[*].type`. */
31
+ export declare const MESSAGE_ITEM_TYPE_NONE = 0;
32
+ export declare const MESSAGE_ITEM_TYPE_TEXT = 1;
33
+ export declare const MESSAGE_ITEM_TYPE_IMAGE = 2;
34
+ export declare const MESSAGE_ITEM_TYPE_VOICE = 3;
35
+ export declare const MESSAGE_ITEM_TYPE_FILE = 4;
36
+ export declare const MESSAGE_ITEM_TYPE_VIDEO = 5;
37
+ /** CDN media reference; Tencent outbound uses base64 of the ASCII hex AES key. */
38
+ export interface ILinkCDNMedia {
39
+ /** Encrypted download query parameter for the CDN URL. */
40
+ encrypt_query_param?: string;
41
+ /** Base64 key payload (32-char ASCII hex for Tencent 2.4.6 outbound). */
42
+ aes_key?: string;
43
+ /** 0 = only file id encrypted, 1 = thumbnail/mid image info packaged. */
44
+ encrypt_type?: number;
45
+ /** Full download URL (server-returned). */
46
+ full_url?: string;
47
+ }
48
+ export interface ILinkTextItem {
49
+ text?: string;
50
+ }
51
+ export interface ILinkImageItem {
52
+ media?: ILinkCDNMedia;
53
+ thumb_media?: ILinkCDNMedia;
54
+ /** Raw AES-128 key as hex string (16 bytes); preferred for inbound decryption. */
55
+ aeskey?: string;
56
+ url?: string;
57
+ mid_size?: number;
58
+ thumb_size?: number;
59
+ }
60
+ export interface ILinkVoiceItem {
61
+ media?: ILinkCDNMedia;
62
+ /** 1=pcm 2=adpcm 3=feature 4=speex 5=amr 6=silk 7=mp3 8=ogg-speex. */
63
+ encode_type?: number;
64
+ bits_per_sample?: number;
65
+ sample_rate?: number;
66
+ /** Voice length in ms. */
67
+ playtime?: number;
68
+ /** Voice transcription text. */
69
+ text?: string;
70
+ }
71
+ export interface ILinkFileItem {
72
+ media?: ILinkCDNMedia;
73
+ file_name?: string;
74
+ md5?: string;
75
+ len?: string;
76
+ }
77
+ export interface ILinkVideoItem {
78
+ media?: ILinkCDNMedia;
79
+ video_size?: number;
80
+ play_length?: number;
81
+ video_md5?: string;
82
+ thumb_media?: ILinkCDNMedia;
83
+ thumb_size?: number;
84
+ }
85
+ export interface ILinkRefMessage {
86
+ message_item?: ILinkMessageItem;
87
+ title?: string;
88
+ }
89
+ /** One item inside `item_list`. */
90
+ export interface ILinkMessageItem {
91
+ type?: number;
92
+ create_time_ms?: number;
93
+ update_time_ms?: number;
94
+ is_completed?: boolean;
95
+ msg_id?: string;
96
+ ref_msg?: ILinkRefMessage;
97
+ text_item?: ILinkTextItem;
98
+ image_item?: ILinkImageItem;
99
+ voice_item?: ILinkVoiceItem;
100
+ file_item?: ILinkFileItem;
101
+ video_item?: ILinkVideoItem;
102
+ tool_call_start_item?: {
103
+ tool_name?: string;
104
+ tool_call_id?: string;
105
+ };
106
+ tool_call_result_item?: {
107
+ tool_name?: string;
108
+ tool_call_id?: string;
109
+ status?: string;
110
+ };
111
+ }
112
+ /** Unified inbound message delivered by `getUpdates`. */
113
+ export interface ILinkMessage {
114
+ seq?: number;
115
+ message_id?: number;
116
+ from_user_id?: string;
117
+ to_user_id?: string;
118
+ client_id?: string;
119
+ create_time_ms?: number;
120
+ update_time_ms?: number;
121
+ session_id?: string;
122
+ group_id?: string;
123
+ message_type?: number;
124
+ message_state?: number;
125
+ item_list?: ILinkMessageItem[];
126
+ context_token?: string;
127
+ run_id?: string;
128
+ }
129
+ /** `getUpdates` request body. */
130
+ export interface ILinkGetUpdatesRequest {
131
+ /** Full context buffer cached locally; send `''` when none. */
132
+ get_updates_buf?: string;
133
+ base_info: ILinkBaseInfo;
134
+ }
135
+ /** `getUpdates` response. */
136
+ export interface ILinkGetUpdatesResponse {
137
+ ret?: number;
138
+ /** Server error code (e.g. -14 = session stale token). */
139
+ errcode?: number;
140
+ errmsg?: string;
141
+ msgs?: ILinkMessage[];
142
+ /** Full context buffer to cache locally and send on the next request. */
143
+ get_updates_buf?: string;
144
+ /** Server-suggested timeout (ms) for the next getUpdates long-poll. */
145
+ longpolling_timeout_ms?: number;
146
+ }
147
+ /** `sendmessage` request wrapping a single message. */
148
+ export interface ILinkSendMessageRequest {
149
+ msg?: ILinkMessage;
150
+ base_info?: ILinkBaseInfo;
151
+ }
152
+ export interface ILinkSendMessageResponse {
153
+ ret?: number;
154
+ errmsg?: string;
155
+ }
156
+ /** `getconfig` request+response. */
157
+ export interface ILinkGetConfigRequest {
158
+ ilink_user_id?: string;
159
+ context_token?: string;
160
+ base_info?: ILinkBaseInfo;
161
+ }
162
+ export interface ILinkGetConfigResponse {
163
+ ret?: number;
164
+ errmsg?: string;
165
+ /** Base64-encoded typing ticket for `sendtyping`. */
166
+ typing_ticket?: string;
167
+ }
168
+ /**
169
+ * Typing status sent to `sendtyping`:
170
+ * 1 = typing (default), 2 = cancel typing.
171
+ */
172
+ export declare const TYPING_STATUS_TYPING = 1;
173
+ export declare const TYPING_STATUS_CANCEL = 2;
174
+ export interface ILinkSendTypingRequest {
175
+ ilink_user_id?: string;
176
+ typing_ticket?: string;
177
+ status?: number;
178
+ base_info?: ILinkBaseInfo;
179
+ }
180
+ export interface ILinkSendTypingResponse {
181
+ ret?: number;
182
+ errmsg?: string;
183
+ }
184
+ /** `get_bot_qrcode` response. */
185
+ export interface ILinkQrCodeResponse {
186
+ qrcode: string;
187
+ qrcode_img_content: string;
188
+ }
189
+ /** QR login status state machine (full upstream fidelity kept). */
190
+ export type ILinkQrStatus = 'wait' | 'scaned' | 'confirmed' | 'expired' | 'need_verifycode' | 'verify_code_blocked' | 'scaned_but_redirect' | 'binded_redirect';
191
+ /** `get_qrcode_status` response. */
192
+ export interface ILinkQrStatusResponse {
193
+ status?: ILinkQrStatus;
194
+ /** Bot token issued on `confirmed`. NEVER logged. */
195
+ bot_token?: string;
196
+ /** Remote bot identity issued on `confirmed`. */
197
+ ilink_bot_id?: string;
198
+ /** Effective API base URL on `confirmed`. */
199
+ baseurl?: string;
200
+ /** Weixin user id of the person who scanned. */
201
+ ilink_user_id?: string;
202
+ /** New host to redirect polling to on `scaned_but_redirect`. */
203
+ redirect_host?: string;
204
+ }
205
+ /** `getuploadurl` request/response (WX5 media scaffold). */
206
+ export interface ILinkGetUploadUrlRequest {
207
+ filekey?: string;
208
+ media_type?: number;
209
+ to_user_id?: string;
210
+ rawsize?: number;
211
+ rawfilemd5?: string;
212
+ filesize?: number;
213
+ thumb_rawsize?: number;
214
+ thumb_rawfilemd5?: string;
215
+ thumb_filesize?: number;
216
+ no_need_thumb?: boolean;
217
+ aeskey?: string;
218
+ base_info?: ILinkBaseInfo;
219
+ }
220
+ export interface ILinkGetUploadUrlResponse {
221
+ upload_param?: string;
222
+ thumb_upload_param?: string;
223
+ upload_full_url?: string;
224
+ }
225
+ /** Notify lifecycle responses. */
226
+ export interface ILinkNotifyResponse {
227
+ ret?: number;
228
+ errmsg?: string;
229
+ }
230
+ /** Inbound metadata attached when mapping an iLink message. */
231
+ export interface WeixinInboundMeta {
232
+ channel: ChannelId;
233
+ accountId: string;
234
+ }
235
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/ilink/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /** Enum values for `message_type`. */
2
+ export const MESSAGE_TYPE_USER = 1;
3
+ export const MESSAGE_TYPE_BOT = 2;
4
+ /** Enum values for `message_state`. */
5
+ export const MESSAGE_STATE_NEW = 0;
6
+ export const MESSAGE_STATE_GENERATING = 1;
7
+ export const MESSAGE_STATE_FINISH = 2;
8
+ /** Enum values for `item_list[*].type`. */
9
+ export const MESSAGE_ITEM_TYPE_NONE = 0;
10
+ export const MESSAGE_ITEM_TYPE_TEXT = 1;
11
+ export const MESSAGE_ITEM_TYPE_IMAGE = 2;
12
+ export const MESSAGE_ITEM_TYPE_VOICE = 3;
13
+ export const MESSAGE_ITEM_TYPE_FILE = 4;
14
+ export const MESSAGE_ITEM_TYPE_VIDEO = 5;
15
+ /**
16
+ * Typing status sent to `sendtyping`:
17
+ * 1 = typing (default), 2 = cancel typing.
18
+ */
19
+ export const TYPING_STATUS_TYPING = 1;
20
+ export const TYPING_STATUS_CANCEL = 2;
21
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/ilink/types.ts"],"names":[],"mappings":"AAwBA,sCAAsC;AACtC,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC;AACnC,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAElC,uCAAuC;AACvC,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC;AACnC,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC;AAC1C,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAEtC,2CAA2C;AAC3C,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AACxC,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AACxC,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC;AACzC,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC;AACzC,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AACxC,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC;AA6IzC;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC;AACtC,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC"}
package/lib/index.d.ts ADDED
@@ -0,0 +1,50 @@
1
+ /**
2
+ * @krischoichoi/channel-weixin — direct Tencent Weixin iLink channel adapter.
3
+ *
4
+ * Replaces the old self-hosted HTTP gateway client with a direct iLink client
5
+ * (QR login, getUpdates long-poll, sendmessage). Streaming is `buffered`.
6
+ */
7
+ import { type Context } from '@deepseek-ai/cordis';
8
+ import type { WeixinConfig, WeixinConfigLive } from './config.js';
9
+ import { Config } from './config.js';
10
+ import { type WeixinAdapterDeps } from './adapter.js';
11
+ export declare const name = "channel-weixin";
12
+ export declare const inject: string[];
13
+ export { Config };
14
+ export type { WeixinConfigLive } from './config.js';
15
+ export { WeixinAdapter, type WeixinAdapterDeps } from './adapter.js';
16
+ export { createWeixinDefinition, type WeixinDefinitionOptions, } from './definition.js';
17
+ export { ILinkClient, type ILinkClientOptions } from './ilink/client.js';
18
+ export { buildHeaders, buildWechatUin, encodeClientVersion, clientVersionFromString, type BuildHeadersOptions, } from './ilink/headers.js';
19
+ export { buildBaseInfo } from './ilink/base-info.js';
20
+ export { ILinkError, StaleTokenError, ILinkTimeoutError, ILinkAbortError, ILinkSendError, redactMessage, normalizeILinkError, } from './ilink/errors.js';
21
+ export { WeixinQrAuth, toChannelState, type WeixinQrAuthInternalState, } from './auth/login.js';
22
+ export { AccountCredentialStore, redactCredential, type WeixinAccountCredential, } from './auth/account-store.js';
23
+ export { SyncCursorStore } from './storage/sync-cursor.js';
24
+ export { ContextTokenStore } from './storage/context-token.js';
25
+ export { MemoryDedupStore, PersistentDedupStore, dedupKey, stableHash, type DedupStore, type DedupRecord, type DedupOptions, } from './messaging/dedup.js';
26
+ export { mapInbound, mapItem } from './messaging/mapper.js';
27
+ export { WeixinMonitor, CursorCommitError, type WeixinMonitorOptions } from './messaging/monitor.js';
28
+ export { OutboundSender, buildSendTextPayload, type OutboundSenderOptions } from './messaging/send.js';
29
+ export { TypingController, type TypingControllerOptions } from './messaging/typing.js';
30
+ export { formatQuotedContext } from './messaging/quote.js';
31
+ export { transcodeSilkVoice, SILK_ENCODE_TYPE, DEFAULT_SILK_SAMPLE_RATE, type SilkTranscodeOptions, type SilkTranscodeResult, } from './media/silk-transcode.js';
32
+ export { WeixinConfigManager, type WeixinConfigManagerOptions } from './upstream/config-manager.js';
33
+ export { FetchTransport, type HttpTransport, type HttpRequestInit } from './transport.js';
34
+ export { manifest, type WeixinManifest } from './manifest.js';
35
+ export { createWeixinUpstream, TencentWeixinUpstream, UpstreamCapabilityError, type WeixinUpstream, type WeixinUpstreamHostEnv, type WeixinQrTicket, type WeixinQrAuthPoll, type WeixinAuthCredential, type WeixinMediaRef, type WeixinDownloadResult, type WeixinTextParams, type WeixinImageParams, type WeixinFileParams, type WeixinVideoParams, type WeixinSendResult, } from './upstream/index.js';
36
+ export { aes128Decrypt } from './media/decrypt.js';
37
+ export { aes128Encrypt } from './media/encrypt.js';
38
+ export { downloadMedia, resolveDownloadUrl, type DownloadedMedia, type DownloadMediaOptions, } from './media/download.js';
39
+ export { uploadMedia, buildUploadUrlRequest, aesEcbPaddedSize, WX5_MEDIA_TYPE_IMAGE, WX5_MEDIA_TYPE_VIDEO, WX5_MEDIA_TYPE_FILE, WX5_MEDIA_TYPE_VOICE, type UploadedMedia, type UploadMediaOptions, } from './media/upload.js';
40
+ export { sendMedia, buildSendMediaPayload, type SendMediaOptions, } from './media/send-media.js';
41
+ export type { ILinkBaseInfo, ILinkCDNMedia, ILinkMessage, ILinkMessageItem, ILinkGetUpdatesRequest, ILinkGetUpdatesResponse, ILinkSendMessageRequest, ILinkSendMessageResponse, ILinkQrCodeResponse, ILinkQrStatus, ILinkQrStatusResponse, ILinkGetConfigRequest, ILinkGetConfigResponse, ILinkGetUploadUrlRequest, ILinkGetUploadUrlResponse, ILinkSendTypingRequest, ILinkSendTypingResponse, ILinkNotifyResponse, WeixinInboundMeta, } from './ilink/types.js';
42
+ /**
43
+ * Entry plugin apply. Accepts both the activation-time live shape (volatile
44
+ * fields resolve to `Volatile<T>` handles under Harness 0.2.0) and a plain
45
+ * snapshot (tests / programmatic mounting); plain fields pass through
46
+ * `resolveVolatileConfig` untouched. The shape is validated by Schemastery at
47
+ * the Loader boundary via the attached `Config` schema.
48
+ */
49
+ export declare function apply(ctx: Context, rawConfig: WeixinConfig | WeixinConfigLive, deps?: WeixinAdapterDeps): void;
50
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/lib/index.js ADDED
@@ -0,0 +1,91 @@
1
+ /**
2
+ * @krischoichoi/channel-weixin — direct Tencent Weixin iLink channel adapter.
3
+ *
4
+ * Replaces the old self-hosted HTTP gateway client with a direct iLink client
5
+ * (QR login, getUpdates long-poll, sendmessage). Streaming is `buffered`.
6
+ */
7
+ import {} from '@deepseek-ai/cordis';
8
+ import { mountChannelAdapter, resolveVolatileConfig, resolveVolatileValue } from '@krischoichoi/channel-core';
9
+ import { Config } from './config.js';
10
+ import { WeixinAdapter } from './adapter.js';
11
+ import { createWeixinDefinition } from './definition.js';
12
+ import { AccountCredentialStore } from './auth/account-store.js';
13
+ export const name = 'channel-weixin';
14
+ export const inject = ['channels'];
15
+ // Adapter mounting uses the shared transactional `mountChannelAdapter`
16
+ // from @krischoichoi/channel-core (doc section 5): register -> start; on start error
17
+ // abort + best-effort stop + unregister + rethrow; on unload abort + stop + unregister.
18
+ export { Config };
19
+ export { WeixinAdapter } from './adapter.js';
20
+ export { createWeixinDefinition, } from './definition.js';
21
+ export { ILinkClient } from './ilink/client.js';
22
+ export { buildHeaders, buildWechatUin, encodeClientVersion, clientVersionFromString, } from './ilink/headers.js';
23
+ export { buildBaseInfo } from './ilink/base-info.js';
24
+ export { ILinkError, StaleTokenError, ILinkTimeoutError, ILinkAbortError, ILinkSendError, redactMessage, normalizeILinkError, } from './ilink/errors.js';
25
+ export { WeixinQrAuth, toChannelState, } from './auth/login.js';
26
+ export { AccountCredentialStore, redactCredential, } from './auth/account-store.js';
27
+ export { SyncCursorStore } from './storage/sync-cursor.js';
28
+ export { ContextTokenStore } from './storage/context-token.js';
29
+ export { MemoryDedupStore, PersistentDedupStore, dedupKey, stableHash, } from './messaging/dedup.js';
30
+ export { mapInbound, mapItem } from './messaging/mapper.js';
31
+ export { WeixinMonitor, CursorCommitError } from './messaging/monitor.js';
32
+ export { OutboundSender, buildSendTextPayload } from './messaging/send.js';
33
+ export { TypingController } from './messaging/typing.js';
34
+ export { formatQuotedContext } from './messaging/quote.js';
35
+ export { transcodeSilkVoice, SILK_ENCODE_TYPE, DEFAULT_SILK_SAMPLE_RATE, } from './media/silk-transcode.js';
36
+ export { WeixinConfigManager } from './upstream/config-manager.js';
37
+ export { FetchTransport } from './transport.js';
38
+ export { manifest } from './manifest.js';
39
+ export { createWeixinUpstream, TencentWeixinUpstream, UpstreamCapabilityError, } from './upstream/index.js';
40
+ // WX5 media.
41
+ export { aes128Decrypt } from './media/decrypt.js';
42
+ export { aes128Encrypt } from './media/encrypt.js';
43
+ export { downloadMedia, resolveDownloadUrl, } from './media/download.js';
44
+ export { uploadMedia, buildUploadUrlRequest, aesEcbPaddedSize, WX5_MEDIA_TYPE_IMAGE, WX5_MEDIA_TYPE_VIDEO, WX5_MEDIA_TYPE_FILE, WX5_MEDIA_TYPE_VOICE, } from './media/upload.js';
45
+ export { sendMedia, buildSendMediaPayload, } from './media/send-media.js';
46
+ /**
47
+ * Entry plugin apply. Accepts both the activation-time live shape (volatile
48
+ * fields resolve to `Volatile<T>` handles under Harness 0.2.0) and a plain
49
+ * snapshot (tests / programmatic mounting); plain fields pass through
50
+ * `resolveVolatileConfig` untouched. The shape is validated by Schemastery at
51
+ * the Loader boundary via the attached `Config` schema.
52
+ */
53
+ export function apply(ctx, rawConfig, deps = {}) {
54
+ const config = resolveVolatileConfig(rawConfig);
55
+ const control = ctx.get('channelControl');
56
+ if (control) {
57
+ // Control-plane entry (doc §43): register the definition EVEN when
58
+ // disabled — the control plane auto-starts it (autoStart) and a disabled
59
+ // definition must stay visible so the Web control plane can re-enable it
60
+ // later (doc §19/§20). The M1 QR flow is driven through the mounted adapter.
61
+ const settings = ctx.get('settings');
62
+ // Weixin owner auto-discovery: the control plane never reads
63
+ // weixin credential storage; a closure here maps the stored scanning
64
+ // user's canonical id out of the platform's own AccountCredentialStore.
65
+ const resolveOwnerIdentity = async (accountId) => {
66
+ const store = new AccountCredentialStore({
67
+ secrets: ctx.channels.resources.secrets,
68
+ storage: ctx.channels.resources.storage,
69
+ accountId,
70
+ });
71
+ const credential = await store.load();
72
+ return credential?.userId;
73
+ };
74
+ control.definitions.register(createWeixinDefinition({
75
+ config,
76
+ deps,
77
+ getAdapter: () => control.runtime?.adapter('weixin'),
78
+ persistEnabled: (enabled) => settings?.update('channels-weixin', { enabled }) ?? Promise.resolve(),
79
+ resolveOwnerIdentity,
80
+ }));
81
+ return;
82
+ }
83
+ // Legacy headless/standalone path (no channel-control): mount as today.
84
+ // There is no directory/control surface to re-enable a disabled channel, so
85
+ // the config `enabled` gate still applies (doc §20).
86
+ if (!resolveVolatileValue(config.enabled))
87
+ return;
88
+ const adapter = new WeixinAdapter(config, deps);
89
+ mountChannelAdapter(ctx, adapter, (signal) => ctx.channels.createAdapterContext({ channelId: 'weixin', signal }));
90
+ }
91
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Upstream strategy, per plan §39:
3
+ * 'official-sdk' — consume the official SDK as-is.
4
+ * 'official-host-neutral-subpath' — consume official host-neutral primitives
5
+ * via a single vendor-compat deep-import
6
+ * boundary; composed orchestration stays a
7
+ * thin shim (upstream-gap).
8
+ * 'minimal-official-api-port' — only the minimum official API ported.
9
+ */
10
+ export type UpstreamStrategy = 'official-sdk' | 'official-host-neutral-subpath' | 'minimal-official-api-port' | 'source-port';
11
+ export interface WeixinUpstreamManifest {
12
+ reference: string;
13
+ /**
14
+ * Exact upstream version the adapter was verified against. The 'pending'
15
+ * placeholder is filled ONLY after the live platform gate passes (real
16
+ * Weixin iLink live verification); before then it must stay pending.
17
+ */
18
+ testedVersion: string;
19
+ /**
20
+ * Exact Tencent/openclaw-weixin commit SHA the adapter was verified against.
21
+ * Filled ONLY after the live gate passes (same live-verification rule).
22
+ */
23
+ testedCommit?: string;
24
+ /**
25
+ * Range of upstream versions supported. Currently '*', which must NOT be kept
26
+ * long-term: after live verification, pin the verified commit/range here.
27
+ */
28
+ versionRange: string;
29
+ strategy: UpstreamStrategy;
30
+ protocol: 'weixin-ilink';
31
+ /** Official npm package that provides the protocol (plan §39). */
32
+ packageName: string;
33
+ /** npm package source repository (plan §39). */
34
+ sourceRepository: string;
35
+ /** Contract fixtures directory (plan §39). */
36
+ contractFixtures: readonly string[];
37
+ }
38
+ export interface WeixinManifest {
39
+ id: 'weixin';
40
+ adapterVersion: string;
41
+ upstream: WeixinUpstreamManifest;
42
+ sdk: undefined;
43
+ /**
44
+ * Compatibility state of this adapter against the real Weixin iLink platform.
45
+ *
46
+ * - 'experimental': default BEFORE the live platform gate passes — real-Weixin
47
+ * live verification is still pending, so claiming 'tested' would be false.
48
+ * - 'tested': only after the live gate passes and the real values are recorded
49
+ * in `upstream.testedVersion` / `upstream.testedCommit`.
50
+ */
51
+ status: 'experimental' | 'tested';
52
+ }
53
+ export declare const manifest: WeixinManifest;
54
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAUA;;;;;;;;GAQG;AACH,MAAM,MAAM,gBAAgB,GACxB,cAAc,GACd,+BAA+B,GAC/B,2BAA2B,GAC3B,aAAa,CAAC;AAElB,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,QAAQ,EAAE,cAAc,CAAC;IACzB,kEAAkE;IAClE,WAAW,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,gBAAgB,EAAE,MAAM,CAAC;IACzB,8CAA8C;IAC9C,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,QAAQ,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,sBAAsB,CAAC;IACjC,GAAG,EAAE,SAAS,CAAC;IACf;;;;;;;OAOG;IACH,MAAM,EAAE,cAAc,GAAG,QAAQ,CAAC;CACnC;AAED,eAAO,MAAM,QAAQ,EAAE,cAqBtB,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Weixin upstream compatibility manifest (doc section 35 + plan §39).
3
+ *
4
+ * Structural shape matched to `AdapterManifest` so `channels doctor` and the
5
+ * channel-compat governance read it without a package dependency. Tencent's
6
+ * published plugin is OpenClaw-coupled, so this adapter is an explicit
7
+ * source-port/upstream-gap until Tencent publishes a host-neutral package.
8
+ */
9
+ import pkg from '../package.json' with { type: 'json' };
10
+ export const manifest = {
11
+ id: 'weixin',
12
+ adapterVersion: pkg.version,
13
+ upstream: {
14
+ reference: 'Tencent/openclaw-weixin (source reference; OpenClaw-coupled upstream-gap)',
15
+ // Exact pinned upstream package version consumed via vendor-compat (plan §17/§39).
16
+ testedVersion: '<pending-live-verification>',
17
+ // Placeholder — filled ONLY after the live platform gate passes (see doc R6).
18
+ testedCommit: '<pending-live-verification>',
19
+ // NOTE: must be pinned to the verified commit/range after live verification —
20
+ // do NOT keep versionRange: '*' long-term (doc R6 "不要保留 versionRange: '*' 长期").
21
+ versionRange: '*',
22
+ strategy: 'source-port',
23
+ protocol: 'weixin-ilink',
24
+ // (plan §39) official upstream contract.
25
+ packageName: '@tencent-weixin/openclaw-weixin',
26
+ sourceRepository: 'Tencent/openclaw-weixin',
27
+ contractFixtures: ['fixtures/upstream/weixin/2.4.6/'],
28
+ },
29
+ sdk: undefined,
30
+ status: 'experimental',
31
+ };
32
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,GAAG,MAAM,iBAAiB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AA6DxD,MAAM,CAAC,MAAM,QAAQ,GAAmB;IACtC,EAAE,EAAE,QAAQ;IACZ,cAAc,EAAE,GAAG,CAAC,OAAO;IAC3B,QAAQ,EAAE;QACR,SAAS,EAAE,2EAA2E;QACtF,mFAAmF;QACnF,aAAa,EAAE,6BAA6B;QAC5C,8EAA8E;QAC9E,YAAY,EAAE,6BAA6B;QAC3C,8EAA8E;QAC9E,gFAAgF;QAChF,YAAY,EAAE,GAAG;QACjB,QAAQ,EAAE,aAAa;QACvB,QAAQ,EAAE,cAAc;QACxB,yCAAyC;QACzC,WAAW,EAAE,iCAAiC;QAC9C,gBAAgB,EAAE,yBAAyB;QAC3C,gBAAgB,EAAE,CAAC,iCAAiC,CAAC;KACtD;IACD,GAAG,EAAE,SAAS;IACd,MAAM,EAAE,cAAc;CACvB,CAAC"}
@@ -0,0 +1,3 @@
1
+ /** AES-128-ECB decrypt (PKCS#7 padding). `key` may be 16 raw bytes or hex. */
2
+ export declare function aes128Decrypt(ciphertext: Buffer, key: Buffer | string): Buffer;
3
+ //# sourceMappingURL=decrypt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decrypt.d.ts","sourceRoot":"","sources":["../../src/media/decrypt.ts"],"names":[],"mappings":"AAQA,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAK9E"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * WX5 media — AES-128-ECB decrypt.
3
+ *
4
+ * Tencent's published plugin is OpenClaw-coupled and cannot be used as a DSH
5
+ * runtime dependency. This small source-port intentionally uses Node crypto.
6
+ */
7
+ import { createDecipheriv } from 'node:crypto';
8
+ /** AES-128-ECB decrypt (PKCS#7 padding). `key` may be 16 raw bytes or hex. */
9
+ export function aes128Decrypt(ciphertext, key) {
10
+ const keyBuf = typeof key === 'string' ? Buffer.from(key, 'hex') : key;
11
+ if (keyBuf.length !== 16)
12
+ throw new Error('aes128Decrypt: AES-128 key must be 16 bytes');
13
+ const decipher = createDecipheriv('aes-128-ecb', keyBuf, null);
14
+ return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
15
+ }
16
+ //# sourceMappingURL=decrypt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decrypt.js","sourceRoot":"","sources":["../../src/media/decrypt.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,8EAA8E;AAC9E,MAAM,UAAU,aAAa,CAAC,UAAkB,EAAE,GAAoB;IACpE,MAAM,MAAM,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IACvE,IAAI,MAAM,CAAC,MAAM,KAAK,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACzF,MAAM,QAAQ,GAAG,gBAAgB,CAAC,aAAa,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IAC/D,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;AACxE,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { ILinkCDNMedia } from '../ilink/types.js';
2
+ export interface DownloadedMedia {
3
+ /** Decrypted plaintext bytes. */
4
+ data: Buffer;
5
+ mimeType?: string;
6
+ }
7
+ export interface DownloadMediaOptions {
8
+ cdnBaseUrl: string;
9
+ /** Optional AES-128 key (hex, 16 bytes) to decrypt after download. */
10
+ aesKey?: string;
11
+ /** Optional base64 AES key from the CDN media reference. */
12
+ aesKeyBase64?: string;
13
+ /** Optional MIME type (known from item metadata). */
14
+ mimeType?: string;
15
+ /** Injectable fetch for tests; defaults to globalThis.fetch. */
16
+ fetchImpl?: typeof fetch;
17
+ }
18
+ /** Resolve the CDN download URL for a media reference. */
19
+ export declare function resolveDownloadUrl(media: ILinkCDNMedia, cdnBaseUrl: string): string | undefined;
20
+ /** Download an iLink CDN media reference and AES-decrypt the body. */
21
+ export declare function downloadMedia(media: ILinkCDNMedia, opts: DownloadMediaOptions): Promise<DownloadedMedia>;
22
+ //# sourceMappingURL=download.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../../src/media/download.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,MAAM,WAAW,eAAe;IAC9B,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,sEAAsE;IACtE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED,0DAA0D;AAC1D,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAK/F;AAED,sEAAsE;AACtE,wBAAsB,aAAa,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,CAAC,CAgB9G"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Classification: C — duplicate media download orchestration [@deprecated upstream-gap].
3
+ *
4
+ * CDN download + AES decrypt for inbound media. The official composed flow
5
+ * cdn/pic-decrypt.js is OpenClaw coupled (imports util/logger). The developer
6
+ * AES remains a small local source-port because the Tencent plugin is coupled
7
+ * to OpenClaw. The URL
8
+ * resolution here (legacy <cdnBaseUrl>/<encrypt_query_param>) is DSH glue kept
9
+ * for the verified CDN path (official buildCdnDownloadUrl uses a different URL
10
+ * form). Marked upstream-gap for the orchestration; DO NOT delete wholesale.
11
+ */
12
+ /**
13
+ * WX5 media — CDN download (WX5.1 Image).
14
+ *
15
+ * Resolves the download URL from `full_url` (server-returned) or the CDN base
16
+ * URL + `encrypt_query_param`, fetches the raw body, then AES-128-ECB decrypts
17
+ * it. The AES key source is resolved in priority order:
18
+ * 1. `aesKey` — hex (16 bytes) as surfaced on the message item
19
+ * (`image_item.aeskey`); preferred per the wire comment.
20
+ * 2. `media.aes_key` — base64-encoded bytes (JSON transport convention).
21
+ */
22
+ import { aes128Decrypt } from './decrypt.js';
23
+ /** Resolve the CDN download URL for a media reference. */
24
+ export function resolveDownloadUrl(media, cdnBaseUrl) {
25
+ if (media.full_url)
26
+ return media.full_url;
27
+ const base = cdnBaseUrl.replace(/\/+$/, '');
28
+ if (media.encrypt_query_param)
29
+ return `${base}/${media.encrypt_query_param}`;
30
+ return undefined;
31
+ }
32
+ /** Download an iLink CDN media reference and AES-decrypt the body. */
33
+ export async function downloadMedia(media, opts) {
34
+ const url = resolveDownloadUrl(media, opts.cdnBaseUrl);
35
+ if (!url) {
36
+ throw new Error('downloadMedia: no full_url or encrypt_query_param to resolve a CDN URL');
37
+ }
38
+ const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
39
+ const response = await fetchImpl(url);
40
+ if (!response.ok) {
41
+ throw new Error(`downloadMedia: http ${response.status} on CDN url`);
42
+ }
43
+ const body = Buffer.from(await response.arrayBuffer());
44
+ const key = opts.aesKey ?? opts.aesKeyBase64 ?? media.aes_key ? decodeAesKey(opts, media) : undefined;
45
+ if (!key) {
46
+ return { data: body, mimeType: opts.mimeType };
47
+ }
48
+ return { data: aes128Decrypt(body, key), mimeType: opts.mimeType };
49
+ }
50
+ /**
51
+ * Decode the AES key honoring the two wire forms: hex (item `aeskey`) and
52
+ * base64 (CDN `aes_key`). `aesKey` (hex) is preferred when present.
53
+ */
54
+ function decodeAesKey(opts, media) {
55
+ if (opts.aesKey)
56
+ return opts.aesKey;
57
+ const base64 = opts.aesKeyBase64 ?? media.aes_key;
58
+ if (base64)
59
+ return Buffer.from(base64, 'base64');
60
+ throw new Error('downloadMedia: no AES key to decrypt');
61
+ }
62
+ //# sourceMappingURL=download.js.map