tmc.js 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Taobao Message Channel (tmc.js)
1
+ # tmc.js
2
2
 
3
3
  Events driven and chained Taobao Message Channel(TMC) for NodeJS
4
4
 
@@ -7,9 +7,9 @@ Events driven and chained Taobao Message Channel(TMC) for NodeJS
7
7
  `npm i tmc.js`
8
8
 
9
9
  ```js
10
- import TMC from 'tmc.js';
10
+ import Tmc from 'tmc.js';
11
11
 
12
- new TMC('your_app_key', 'your_app_secret')
12
+ new Tmc('your_app_key', 'your_app_secret')
13
13
  .on('taobao_trade_TradeChanged', msg => console.info(msg))
14
14
  .taobao_trade_TradeClose(msg => console.info(msg))
15
15
  .connect();
@@ -17,7 +17,7 @@ new TMC('your_app_key', 'your_app_secret')
17
17
 
18
18
  ## API
19
19
 
20
- **`new TMC(appKey: string, appSecret: BinaryLike, groupName?: string | object, options?: object)`**
20
+ **`new Tmc(appKey: string, appSecret: BinaryLike, groupName?: string | object, options?: object)`**
21
21
 
22
22
  | 参数 | 类型 | 说明 |
23
23
  | --- | --- | --- |
@@ -31,6 +31,135 @@ new TMC('your_app_key', 'your_app_secret')
31
31
  | options.autoParseContentJson | `boolean` | 自动解析推送消息`$.content.content`字段为对象(默认`true`) |
32
32
  | options.autoReplyConfirmation | `boolean` | 以推送的`$.content.id`字段自动`Confirm`消息(默认`true`) |
33
33
 
34
+ **`tmc.on(topic: string, listener: (this: Tmc, message: Message) => void) => Tmc`**
35
+
36
+ 注册 `topic` 消息通知处理函数,默认已内置 [消息](./types/message.in.d.ts) 说明。
37
+
38
+ **`tmc[<topic>](fn: (this: Tmc, message: Message) => void) => Tmc`**
39
+
40
+ 直接以 `topic` 为键值,注册消息通知处理函数。
41
+
42
+ **`tmc.reconnect(ms: number) => Tmc`**
43
+
44
+ 当消费端 `onerror`/`onclose` 事件发生时,延迟 `ms` 毫秒自动重新建立连接。
45
+
46
+ **`tmc.connect(address?: string) => Tmc`**
47
+
48
+ 消费端发起建立连接 `onopen` 事件,`address` 默认为 `ws://mc.api.taobao.com/`。
49
+
50
+ <details><summary>可选设置的 NODE_DEBUG=< label > 环境变量</summary>
51
+
52
+ | label | 说明 |
53
+ | --- | --- |
54
+ | `tmc` | 开启全部`DEBUG`日志模式
55
+ | `tmc:onping` | 开启 `onping` 时的日志
56
+ | `tmc:onopen` | 开启 `onopen` 时的日志
57
+ | `tmc:onpull` | 开启 `onpull` 时的日志
58
+ | `tmc:onerror` | 开启 `onerror` 时的日志
59
+ | `tmc:onclose` | 开启 `onclose` 时的日志
60
+ | `tmc:onmessage` | 开启全部 `onmessage` 时的日志(即`From`淘宝消息)
61
+ | `tmc:onmessage:connect` | 开启消费端发起连接 `connect` 时的日志
62
+ | `tmc:onmessage:connectack` | 开启消费端回复连接 `connectack` 时的日志
63
+ | `tmc:onmessage:send` | 开启消费端接收到(即`From`淘宝) `send` 的消息时的日志
64
+ | `tmc:onmessage:sendack` | (暂未明确场景)
65
+ | `tmc:onmessage:send:confirm` | 开启消费端回复接收到的(即`From`淘宝消息),发送自动确认 `send:confirm` 时的日志
66
+
67
+ </details>
68
+
69
+ ## 支持的TOPICS
70
+
71
+ <details><summary>共计 81+ 类别,439+ 消息数</summary>
72
+
73
+ | 类别 | 消息数 |
74
+ | --- | --- |
75
+ | 淘宝交易 | 20 |
76
+ | 淘宝退款 | 13 |
77
+ | 淘宝商品 | 13 |
78
+ | 淘宝分销 | 23 |
79
+ | 淘宝点点 | 12 |
80
+ | 淘宝火车票 | 5 |
81
+ | 平台消息 | 7 |
82
+ | 交易全链路 | 3 |
83
+ | 淘宝机票 | 14 |
84
+ | 导购平台 | 21 |
85
+ | 淘宝汽车票 | 4 |
86
+ | 服务市场 | 9 |
87
+ | 天猫服务 | 16 |
88
+ | 天猫美妆 | 2 |
89
+ | 聚石塔 | 9 |
90
+ | 淘宝物流 | 1 |
91
+ | 阿里通信 | 17 |
92
+ | 天猫魔盒 | 2 |
93
+ | OpenIM消息 | 1 |
94
+ | 网上法庭 | 8 |
95
+ | 电子发票 | 20 |
96
+ | 航旅度假交易 | 8 |
97
+ | YunOS YoC | 2 |
98
+ | 阿里物联 | 2 |
99
+ | 全球购跨境物流 | 1 |
100
+ | 零售plus | 8 |
101
+ | 客户运营平台API | 12 |
102
+ | AE-交易 | 10 |
103
+ | 五道口配送 | 1 |
104
+ | 百川 | 2 |
105
+ | 闲鱼 | 14 |
106
+ | 闲鱼回收商消息 | 5 |
107
+ | 零售通POS开放平台消息 | 4 |
108
+ | DPAAS | 6 |
109
+ | AliGenius | 1 |
110
+ | 智慧门店下行消息 | 2 |
111
+ | 渠道中心API | 4 |
112
+ | 五道口订单 | 22 |
113
+ | 信息平台-采购 | 1 |
114
+ | 1688服务市场 | 1 |
115
+ | 酒店商品消息api | 9 |
116
+ | 新零售终端下行消息 | 1 |
117
+ | 新零售终端上行消息 | 4 |
118
+ | 欢行开放平台 | 1 |
119
+ | 阿里发票 | 5 |
120
+ | 大麦票单状态 | 1 |
121
+ | 五道口营销 | 4 |
122
+ | 酒店签约中心消息 | 3 |
123
+ | 蜂鸟物流 | 6 |
124
+ | 商旅API | 3 |
125
+ | 阿里健康-O2O中台 | 2 |
126
+ | 业务平台新零售-消息上行 | 2 |
127
+ | 大麦第三方票务供应商接入 | 5 |
128
+ | TVOS应用审核平台 | 1 |
129
+ | Gifting送礼 | 1 |
130
+ | 五道口商品 | 2 |
131
+ | HOMEAI | 1 |
132
+ | HOMEAI消息对接 | 5 |
133
+ | 零售通_公共 | 8 |
134
+ | 酒店标准库基础信息变更消息 | 2 |
135
+ | 菜鸟发货工作台 | 1 |
136
+ | IOT-智能制造 | 2 |
137
+ | 智能制造API | 1 |
138
+ | IoT售后解决方案 | 1 |
139
+ | OpenMall-API | 5 |
140
+ | 闲鱼已验货 | 6 |
141
+ | 阿里健康三方机构 | 2 |
142
+ | 聚石塔监控告警 | 2 |
143
+ | 大资产拍卖Top端拍品消息 | 2 |
144
+ | AE-任务平台消息 | 1 |
145
+ | 天猫汽车 | 5 |
146
+ | 阿信消息通知前台类目 | 1 |
147
+ | 阿里健康追溯码 | 1 |
148
+ | 自动驾驶API | 3 |
149
+ | MMC五盘货项目 | 5 |
150
+ | 银泰开放平台消息 | 2 |
151
+ | 阿里智付 | 1 |
152
+ | 代发管理 | 2 |
153
+ | 蚂蚁采购 | 1 |
154
+ | 阿里健康&一树-电商中台对接 | 2 |
155
+ | 阿里健康-疫苗 | 1 |
156
+
157
+ </details>
158
+
159
+ ## 链接
160
+
161
+ - [淘宝开放平台-消息服务使用介绍](https://open.taobao.com/doc.htm?docId=101663&docType=1)
162
+
34
163
  ## License
35
164
 
36
165
  [MIT](LICENSE)
package/lib/consumer.js CHANGED
@@ -29,7 +29,7 @@ function ipAddr() {
29
29
  )?.address;
30
30
  }
31
31
 
32
- class TaoMessageComsumer extends EventEmitter {
32
+ class TaoMessageConsumer extends EventEmitter {
33
33
  [kAddress] = 'ws://mc.api.taobao.com/';
34
34
 
35
35
  [kGroupName] = 'default';
@@ -202,5 +202,5 @@ class TaoMessageComsumer extends EventEmitter {
202
202
  }
203
203
  }
204
204
 
205
- module.exports = TaoMessageComsumer;
206
- module.exports.default = TaoMessageComsumer;
205
+ module.exports = TaoMessageConsumer;
206
+ module.exports.default = TaoMessageConsumer;
package/lib/message.js CHANGED
@@ -10,6 +10,9 @@ const {
10
10
  TYPE, CODE, PHRASE, FLAG, TOKEN, CONTENT,
11
11
  } = require('./message-fields');
12
12
 
13
+ const kData = Symbol('kData');
14
+ const kBuffer = Symbol('kBuffer');
15
+
13
16
  class Message {
14
17
  protocolVersion = 2;
15
18
 
@@ -49,7 +52,7 @@ class Message {
49
52
 
50
53
  static from(buf) {
51
54
  /* eslint-disable-next-line no-use-before-define */
52
- return new Decoder(buf).data;
55
+ return new Decoder(buf).message;
53
56
  }
54
57
  }
55
58
 
@@ -77,53 +80,53 @@ function pick(size, method, ...value) {
77
80
  }
78
81
 
79
82
  class Encoder {
80
- buffers = [];
83
+ [kBuffer] = [];
81
84
 
82
- data;
85
+ [kData];
83
86
 
84
87
  constructor(message) {
85
88
  if (!(message instanceof Message)) {
86
89
  throw new TypeError('Must be an instance Message here.');
87
90
  }
88
- this.data = message;
91
+ this[kData] = message;
89
92
  }
90
93
 
91
94
  compress() {
92
- this.put(this.data.protocolVersion).put(this.data[TYPE]);
95
+ this.put(this[kData].protocolVersion).put(this[kData][TYPE]);
93
96
  /* eslint-disable-next-line no-unused-expressions */
94
- this.data[CODE] && this.putShort(StatusCode).putShort(this.data[CODE]);
97
+ this[kData][CODE] && this.putShort(StatusCode).putShort(this[kData][CODE]);
95
98
  /* eslint-disable-next-line no-unused-expressions */
96
- this.data[PHRASE] && this.putShort(StatusPhrase).writeCountedString(this.data[PHRASE]);
99
+ this[kData][PHRASE] && this.putShort(StatusPhrase).writeCountedString(this[kData][PHRASE]);
97
100
  /* eslint-disable-next-line no-unused-expressions */
98
- this.data[FLAG] && this.putShort(Flag).putInt(this.data[FLAG]);
101
+ this[kData][FLAG] && this.putShort(Flag).putInt(this[kData][FLAG]);
99
102
  /* eslint-disable-next-line no-unused-expressions */
100
- this.data[TOKEN] && this.putShort(Token).writeCountedString(this.data[TOKEN]);
101
- Object.entries(this.data[CONTENT] || {}).forEach(([k, v]) => this.putShort(Custom).writeCountedString(k).writeCustomValue(v));
103
+ this[kData][TOKEN] && this.putShort(Token).writeCountedString(this[kData][TOKEN]);
104
+ Object.entries(this[kData][CONTENT] || {}).forEach(([k, v]) => this.putShort(Custom).writeCountedString(k).writeCustomValue(v));
102
105
  this.putShort(EndOfHeaders);
103
106
 
104
107
  return this;
105
108
  }
106
109
 
107
110
  put(value) {
108
- this.buffers.push(pick(1, writeInt8, Number(value)));
111
+ this[kBuffer].push(pick(1, writeInt8, Number(value)));
109
112
 
110
113
  return this;
111
114
  }
112
115
 
113
116
  putShort(value) {
114
- this.buffers.push(pick(2, writeInt16LE, Number(value)));
117
+ this[kBuffer].push(pick(2, writeInt16LE, Number(value)));
115
118
 
116
119
  return this;
117
120
  }
118
121
 
119
122
  putInt(value) {
120
- this.buffers.push(pick(4, writeInt32LE, Number(value)));
123
+ this[kBuffer].push(pick(4, writeInt32LE, Number(value)));
121
124
 
122
125
  return this;
123
126
  }
124
127
 
125
128
  putLong(value) {
126
- this.buffers.push(pick(8, writeBigInt64LE, BigInt(value)));
129
+ this[kBuffer].push(pick(8, writeBigInt64LE, BigInt(value)));
127
130
 
128
131
  return this;
129
132
  }
@@ -132,7 +135,7 @@ class Encoder {
132
135
  const len = value ? Buffer.byteLength(value) : 0;
133
136
  this.putInt(len);
134
137
  /* eslint-disable-next-line no-unused-expressions */
135
- len && this.buffers.push(pick(len, write, value, utf8));
138
+ len && this[kBuffer].push(pick(len, write, value, utf8));
136
139
 
137
140
  return this;
138
141
  }
@@ -173,15 +176,17 @@ class Encoder {
173
176
 
174
177
  if (Buffer.isBuffer(value)) {
175
178
  this.put(ByteArray).putInt(value.length);
176
- this.buffers.push(value);
179
+ this[kBuffer].push(value);
177
180
  }
178
181
 
179
182
  return this;
180
183
  }
181
184
 
182
- get buffer() { return Buffer.concat(this.compress().buffers); }
185
+ get buffer() { return Buffer.concat(this.compress()[kBuffer]); }
183
186
  }
184
187
 
188
+ const kOffset = Symbol('kOffset');
189
+
185
190
  const readInt8 = 'readInt8';
186
191
 
187
192
  const readInt16LE = 'readInt16LE';
@@ -195,23 +200,23 @@ function read(buffer, method, offset, ...extra) {
195
200
  }
196
201
 
197
202
  class Decoder {
198
- offset = 1;
203
+ [kOffset] = 1;
199
204
 
200
- buffer;
205
+ [kBuffer];
201
206
 
202
- data;
207
+ [kData];
203
208
 
204
209
  constructor(buf) {
205
210
  if (!Buffer.isBuffer(buf)) {
206
211
  throw new TypeError('Must be an instance Buffer here.');
207
212
  }
208
- this.buffer = buf;
209
- this.data = new Message();
213
+ this[kBuffer] = buf;
214
+ this[kData] = new Message();
210
215
  this.extract();
211
216
  }
212
217
 
213
218
  extract() {
214
- this.data.with(TYPE, this.reset().get());
219
+ this[kData].with(TYPE, this.reset().get());
215
220
 
216
221
  let headerType;
217
222
  do {
@@ -219,47 +224,47 @@ class Decoder {
219
224
  this[`pick${headerType}`]();
220
225
  } while (headerType !== EndOfHeaders);
221
226
 
222
- this.reset();
227
+ return this.reset();
223
228
  }
224
229
 
225
- [`pick${EndOfHeaders}`]() { return this.data; }
230
+ [`pick${EndOfHeaders}`]() { return this[kData]; }
226
231
 
227
- [`pick${Custom}`]() { return this.data.with(this.readCountedString(), this.readCustomValue()); }
232
+ [`pick${Custom}`]() { return this[kData].with(this.readCountedString(), this.readCustomValue()); }
228
233
 
229
- [`pick${StatusCode}`]() { return this.data.with(CODE, this.getInt()); }
234
+ [`pick${StatusCode}`]() { return this[kData].with(CODE, this.getInt()); }
230
235
 
231
- [`pick${StatusPhrase}`]() { return this.data.with(PHRASE, this.readCountedString()); }
236
+ [`pick${StatusPhrase}`]() { return this[kData].with(PHRASE, this.readCountedString()); }
232
237
 
233
- [`pick${Flag}`]() { return this.data.with(FLAG, this.getInt()); }
238
+ [`pick${Flag}`]() { return this[kData].with(FLAG, this.getInt()); }
234
239
 
235
- [`pick${Token}`]() { return this.data.with(TOKEN, this.readCountedString()); }
240
+ [`pick${Token}`]() { return this[kData].with(TOKEN, this.readCountedString()); }
236
241
 
237
242
  reset() {
238
- this.offset = 1;
243
+ this[kOffset] = 1;
239
244
  return this;
240
245
  }
241
246
 
242
247
  get() {
243
- const value = read(this.buffer, readInt8, this.offset);
244
- this.offset += 1;
248
+ const value = read(this[kBuffer], readInt8, this[kOffset]);
249
+ this[kOffset] += 1;
245
250
  return Number(value);
246
251
  }
247
252
 
248
253
  getShort() {
249
- const value = read(this.buffer, readInt16LE, this.offset);
250
- this.offset += 2;
254
+ const value = read(this[kBuffer], readInt16LE, this[kOffset]);
255
+ this[kOffset] += 2;
251
256
  return Number(value);
252
257
  }
253
258
 
254
259
  getInt() {
255
- const value = read(this.buffer, readInt32LE, this.offset);
256
- this.offset += 4;
260
+ const value = read(this[kBuffer], readInt32LE, this[kOffset]);
261
+ this[kOffset] += 4;
257
262
  return Number(value);
258
263
  }
259
264
 
260
265
  getLong() {
261
- const value = read(this.buffer, readBigInt64LE, this.offset);
262
- this.offset += 8;
266
+ const value = read(this[kBuffer], readBigInt64LE, this[kOffset]);
267
+ this[kOffset] += 8;
263
268
  return BigInt(value);
264
269
  }
265
270
 
@@ -268,8 +273,8 @@ class Decoder {
268
273
  if (size === 0) {
269
274
  return null;
270
275
  }
271
- const buf = this.buffer.subarray(this.offset, this.offset + size);
272
- this.offset += size;
276
+ const buf = this[kBuffer].subarray(this[kOffset], this[kOffset] + size);
277
+ this[kOffset] += size;
273
278
  return buf;
274
279
  }
275
280
 
@@ -293,7 +298,7 @@ class Decoder {
293
298
 
294
299
  [`parse${CountedString}`]() { return this.readCountedString(); }
295
300
 
296
- get message() { return this.data; }
301
+ get message() { return this[kData]; }
297
302
  }
298
303
 
299
304
  module.exports = Message;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tmc.js",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Events driven and chained Taobao Message Channel(TMC) for NodeJS",
5
5
  "author": "James ZHANG",
6
6
  "license": "MIT",
@@ -0,0 +1,21 @@
1
+ declare namespace HeaderType {
2
+ type EndOfHeaders = 0;
3
+ type Custom = 1;
4
+ type StatusCode = 2;
5
+ type StatusPhrase = 3;
6
+ type Flag = 4;
7
+ type Token = 5;
8
+ interface includes {
9
+ (value: any): boolean;
10
+ }
11
+ }
12
+
13
+ declare class HeaderType {
14
+ static EndOfHeaders: HeaderType.EndOfHeaders;
15
+ static Custom: HeaderType.Custom;
16
+ static StatusCode: HeaderType.StatusCode;
17
+ static StatusPhrase: HeaderType.StatusPhrase;
18
+ static Flag: HeaderType.Flag;
19
+ static Token: HeaderType.Token;
20
+ static includes: HeaderType.includes;
21
+ }