tmc.js 0.3.2 → 0.3.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.
- package/README.md +25 -1
- package/lib/consumer.js +15 -13
- package/lib/message-fields.js +20 -0
- package/package.json +1 -1
- package/types/index.d.ts +12 -0
- package/types/message-fields.d.ts +10 -0
- package/types/message.d.ts +4 -4
- package/types/message.in.d.ts +4 -0
- package/types/tmall.d.ts +19 -0
package/README.md
CHANGED
|
@@ -9,6 +9,12 @@ Events driven and chained Taobao Message Channel(TMC) for NodeJS
|
|
|
9
9
|
[](https://www.npmjs.com/package/tmc.js)
|
|
10
10
|
[](https://www.npmjs.com/package/tmc.js)
|
|
11
11
|
|
|
12
|
+
## 设计
|
|
13
|
+
|
|
14
|
+
核心包以事件作为驱动,通过注册`TOPIC`回调处理函数,实现了TMC产品服务的消息消费处理能力,同时通过`Proxy`代理,以`TOPIC`作为键值,平序注册消息消费处理函数,序图如下:
|
|
15
|
+
|
|
16
|
+
[](./.github/sdk-sequence.mmd)
|
|
17
|
+
|
|
12
18
|
## 使用
|
|
13
19
|
|
|
14
20
|
`npm i tmc.js`
|
|
@@ -54,6 +60,24 @@ new Tmc('your_app_key', 'your_app_secret')
|
|
|
54
60
|
|
|
55
61
|
消费端发起建立连接 `onopen` 事件,`address` 默认为 `ws://mc.api.taobao.com/`。
|
|
56
62
|
|
|
63
|
+
**`tmc.send(msg: Message, options?: { mask?: true, binary?: true }, cb?: (err: Error) => void) => void`**
|
|
64
|
+
|
|
65
|
+
实例化后,当自动应答确认消息无法满足需求的时候,比如消息处理失败,需要`Publisher`再次重推消息,在实例初始化时置`options.autoReplyConfirmation=false`,则在消息处理函数内,可以通过 `this.send()` 函数回复`确认`或者`失败`消息。例如:
|
|
66
|
+
|
|
67
|
+
```js
|
|
68
|
+
new Tmc('your_app_key', 'your_app_secret', { autoReplyConfirmation: false })
|
|
69
|
+
.taobao_trade_TradeDelayConfirmPay(function needDoubleReriesThenConfirm(msg) {
|
|
70
|
+
if (msg instanceof Message && msg.content?.reried === 0) {
|
|
71
|
+
this.send(
|
|
72
|
+
new Message(MessageType.SENDACK, MessageKind.Failed)
|
|
73
|
+
.with(MessageFields.ID, msg.content?.id)
|
|
74
|
+
.with(MessageFields.MSG, 'Something went wrong, please retries this ID.')
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
.connect();
|
|
79
|
+
```
|
|
80
|
+
|
|
57
81
|
<details><summary>可选设置的 NODE_DEBUG=< label > 环境变量</summary>
|
|
58
82
|
|
|
59
83
|
| label | 说明 |
|
|
@@ -63,7 +87,7 @@ new Tmc('your_app_key', 'your_app_secret')
|
|
|
63
87
|
| `tmc:onpull` | 开启 `onpull` 时的日志
|
|
64
88
|
| `tmc:onerror` | 开启 `onerror` 时的日志
|
|
65
89
|
| `tmc:onclose` | 开启 `onclose` 时的日志
|
|
66
|
-
| `tmc:onmessage
|
|
90
|
+
| `tmc:onmessage*` | 开启全部 `onmessage` 时的日志(即`From`淘宝消息)
|
|
67
91
|
| `tmc:onmessage:connect` | 开启消费端发起连接 `connect` 时的日志
|
|
68
92
|
| `tmc:onmessage:connectack` | 开启消费端回复连接 `connectack` 时的日志
|
|
69
93
|
| `tmc:onmessage:send` | 开启消费端接收到(即`From`淘宝) `send` 的消息时的日志
|
package/lib/consumer.js
CHANGED
|
@@ -92,6 +92,11 @@ class TaoMessageConsumer extends EventEmitter {
|
|
|
92
92
|
).update(sk).digest('hex').toUpperCase();
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
/** @since v0.3.4 */
|
|
96
|
+
send(data, options = { mask: true, binary: true }, cb = undefined) {
|
|
97
|
+
if (data instanceof Message) { this[kWebSocket]?.send(data.with(TOKEN, this[kToken]).buffer, options, cb); }
|
|
98
|
+
}
|
|
99
|
+
|
|
95
100
|
onopen() {
|
|
96
101
|
const now = `${Date.now()}`;
|
|
97
102
|
const msg = new Message(CONNECT)
|
|
@@ -104,7 +109,7 @@ class TaoMessageConsumer extends EventEmitter {
|
|
|
104
109
|
|
|
105
110
|
logger.onopen(JSONB.stringify(msg));
|
|
106
111
|
|
|
107
|
-
this
|
|
112
|
+
this.send(msg);
|
|
108
113
|
|
|
109
114
|
if (this[kOptions].intervalId) { clearInterval(this[kOptions].intervalId); }
|
|
110
115
|
|
|
@@ -114,7 +119,7 @@ class TaoMessageConsumer extends EventEmitter {
|
|
|
114
119
|
onpull() {
|
|
115
120
|
const msg = new Message(SEND, PullRequest).with(TOKEN, this[kToken]);
|
|
116
121
|
logger.onpull(JSONB.stringify(msg));
|
|
117
|
-
this
|
|
122
|
+
this.send(msg);
|
|
118
123
|
}
|
|
119
124
|
|
|
120
125
|
onping(data) {
|
|
@@ -142,7 +147,7 @@ class TaoMessageConsumer extends EventEmitter {
|
|
|
142
147
|
if (this[kOptions].autoReplyConfirmation && msg && msg[CONTENT] && msg[CONTENT][ID]) {
|
|
143
148
|
const reply = new Message(SEND, Confirm).with(TOKEN, this[kToken]).with(ID, msg[CONTENT][ID]);
|
|
144
149
|
logger.onmessage[SEND][Confirm](JSONB.stringify(reply));
|
|
145
|
-
this
|
|
150
|
+
this.send(reply);
|
|
146
151
|
}
|
|
147
152
|
}
|
|
148
153
|
|
|
@@ -178,6 +183,7 @@ class TaoMessageConsumer extends EventEmitter {
|
|
|
178
183
|
if (this[kOptions].intervalId) { this[kOptions].intervalId = clearInterval(this[kOptions].intervalId); }
|
|
179
184
|
if (this[kOptions].timeoutId) { this[kOptions].timeoutId = clearTimeout(this[kOptions].timeoutId); }
|
|
180
185
|
|
|
186
|
+
this[kToken] = undefined;
|
|
181
187
|
this[kWebSocket] = undefined;
|
|
182
188
|
this[kOptions].timeoutId = setTimeout(() => this.connect(), ms);
|
|
183
189
|
|
|
@@ -187,16 +193,12 @@ class TaoMessageConsumer extends EventEmitter {
|
|
|
187
193
|
connect(address) {
|
|
188
194
|
if (address) { this[kAddress] = address; }
|
|
189
195
|
|
|
190
|
-
this[kWebSocket]
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
ws.on('ping', (...arg) => this.onping(...arg));
|
|
197
|
-
ws.on('error', (err) => this.onerror(err));
|
|
198
|
-
ws.on('close', (...arg) => this.onclose(...arg));
|
|
199
|
-
ws.on('message', (...arg) => this.onmessage(...arg));
|
|
196
|
+
this[kWebSocket] = new WebSocket(this[kAddress])
|
|
197
|
+
.on('message', (data, isBinary) => this.onmessage(data, isBinary))
|
|
198
|
+
.on('close', (code, reason) => this.onclose(code, reason))
|
|
199
|
+
.on('error', (err) => this.onerror(err))
|
|
200
|
+
.on('ping', (data) => this.onping(data))
|
|
201
|
+
.on('open', () => this.onopen());
|
|
200
202
|
|
|
201
203
|
return this;
|
|
202
204
|
}
|
package/lib/message-fields.js
CHANGED
|
@@ -12,6 +12,11 @@ const SDK = 'sdk';
|
|
|
12
12
|
const INTRANET_IP = 'intranet_ip';
|
|
13
13
|
const ID = 'id';
|
|
14
14
|
const TOPIC = 'topic';
|
|
15
|
+
const MSG = 'msg';
|
|
16
|
+
const DATAID = 'dataid';
|
|
17
|
+
const USERID = 'userid';
|
|
18
|
+
const OUTTIME = 'outtime';
|
|
19
|
+
const PUBLISHER = 'publisher';
|
|
15
20
|
|
|
16
21
|
class MessageFields {
|
|
17
22
|
static TYPE = TYPE;
|
|
@@ -41,6 +46,16 @@ class MessageFields {
|
|
|
41
46
|
static ID = ID;
|
|
42
47
|
|
|
43
48
|
static TOPIC = TOPIC;
|
|
49
|
+
|
|
50
|
+
static MSG = MSG;
|
|
51
|
+
|
|
52
|
+
static DATAID = DATAID;
|
|
53
|
+
|
|
54
|
+
static USERID = USERID;
|
|
55
|
+
|
|
56
|
+
static OUTTIME = OUTTIME;
|
|
57
|
+
|
|
58
|
+
static PUBLISHER = PUBLISHER;
|
|
44
59
|
}
|
|
45
60
|
|
|
46
61
|
module.exports = MessageFields;
|
|
@@ -59,3 +74,8 @@ module.exports.SDK = SDK;
|
|
|
59
74
|
module.exports.INTRANET_IP = INTRANET_IP;
|
|
60
75
|
module.exports.ID = ID;
|
|
61
76
|
module.exports.TOPIC = TOPIC;
|
|
77
|
+
module.exports.MSG = MSG;
|
|
78
|
+
module.exports.DATAID = DATAID;
|
|
79
|
+
module.exports.USERID = USERID;
|
|
80
|
+
module.exports.OUTTIME = OUTTIME;
|
|
81
|
+
module.exports.PUBLISHER = PUBLISHER;
|
package/package.json
CHANGED
package/types/index.d.ts
CHANGED
|
@@ -26,6 +26,10 @@ declare interface ConsumerOptions {
|
|
|
26
26
|
declare interface TaoMessageConstractor extends EventEmitter {
|
|
27
27
|
new (appKey: string, appSecret: BinaryLike, groupName?: string | ConsumerOptions, options?: ConsumerOptions): TaoMessageConsumer;
|
|
28
28
|
sign(timestamp: string): string;
|
|
29
|
+
/** @since v0.3.4 */
|
|
30
|
+
send(data: Message, cb?: (err?: Error) => void): void;
|
|
31
|
+
/** @since v0.3.4 */
|
|
32
|
+
send(data: Message, options?: { mask?: true, binary?: true, compress?: boolean, fin?: boolean }, cb?: (err: Error) => void): void;
|
|
29
33
|
onopen(): void;
|
|
30
34
|
onpull(): void;
|
|
31
35
|
onping(data: Buffer): void;
|
|
@@ -784,6 +788,10 @@ declare interface TaoTopicsDescriptor {
|
|
|
784
788
|
tmall_auto_TradeModify(fn: (this: TaoMessageConsumer, message: IncomingMessage.TmallAutoTradeModify) => void): TaoMessageConsumer;
|
|
785
789
|
/** {@link IncomingMessage.TmallAutoTwoWheelsReceiptCreate 天猫汽车 > 天猫二轮车服务工单创建开放} */
|
|
786
790
|
tmall_auto_TwoWheelsReceiptCreate(fn: (this: TaoMessageConsumer, message: IncomingMessage.TmallAutoTwoWheelsReceiptCreate) => void): TaoMessageConsumer;
|
|
791
|
+
/** {@link IncomingMessage.TmallCarContractSign 天猫汽车 > 合同签署消息} */
|
|
792
|
+
tmall_car_ContractSign(fn: (this: TaoMessageConsumer, message: IncomingMessage.TmallCarContractSign) => void): TaoMessageConsumer;
|
|
793
|
+
/** {@link IncomingMessage.TmallCarFinanceMsg 天猫汽车 > 汽车金融消息} */
|
|
794
|
+
tmall_car_FinanceMsg(fn: (this: TaoMessageConsumer, message: IncomingMessage.TmallCarFinanceMsg) => void): TaoMessageConsumer;
|
|
787
795
|
/** {@link IncomingMessage.TmallChannelApplyOrderChange 渠道中心API > 申请单变更消息} */
|
|
788
796
|
tmall_channel_ApplyOrderChange(fn: (this: TaoMessageConsumer, message: IncomingMessage.TmallChannelApplyOrderChange) => void): TaoMessageConsumer;
|
|
789
797
|
/** {@link IncomingMessage.TmallChannelDeliverOrderChange 渠道中心API > 发货单消息变更} */
|
|
@@ -1609,6 +1617,10 @@ declare interface TaoEventsListener {
|
|
|
1609
1617
|
on(topic: 'tmall_auto_TradeModify', listener: (this: TaoMessageConsumer, message: IncomingMessage.TmallAutoTradeModify) => void): TaoMessageConsumer;
|
|
1610
1618
|
/** {@link IncomingMessage.TmallAutoTwoWheelsReceiptCreate 天猫汽车 > 天猫二轮车服务工单创建开放} */
|
|
1611
1619
|
on(topic: 'tmall_auto_TwoWheelsReceiptCreate', listener: (this: TaoMessageConsumer, message: IncomingMessage.TmallAutoTwoWheelsReceiptCreate) => void): TaoMessageConsumer;
|
|
1620
|
+
/** {@link IncomingMessage.TmallCarContractSign 天猫汽车 > 合同签署消息} */
|
|
1621
|
+
on(topic: 'tmall_car_ContractSign', listener: (this: TaoMessageConsumer, message: IncomingMessage.TmallCarContractSign) => void): TaoMessageConsumer;
|
|
1622
|
+
/** {@link IncomingMessage.TmallCarFinanceMsg 天猫汽车 > 汽车金融消息} */
|
|
1623
|
+
on(topic: 'tmall_car_FinanceMsg', listener: (this: TaoMessageConsumer, message: IncomingMessage.TmallCarFinanceMsg) => void): TaoMessageConsumer;
|
|
1612
1624
|
/** {@link IncomingMessage.TmallChannelApplyOrderChange 渠道中心API > 申请单变更消息} */
|
|
1613
1625
|
on(topic: 'tmall_channel_ApplyOrderChange', listener: (this: TaoMessageConsumer, message: IncomingMessage.TmallChannelApplyOrderChange) => void): TaoMessageConsumer;
|
|
1614
1626
|
/** {@link IncomingMessage.TmallChannelDeliverOrderChange 渠道中心API > 发货单消息变更} */
|
|
@@ -13,6 +13,11 @@ declare namespace MessageFields {
|
|
|
13
13
|
type INTRANET_IP = 'intranet_ip';
|
|
14
14
|
type ID = 'id';
|
|
15
15
|
type TOPIC = 'topic';
|
|
16
|
+
type MSG = 'msg';
|
|
17
|
+
type DATAID = 'dataid';
|
|
18
|
+
type USERID = 'userid';
|
|
19
|
+
type OUTTIME = 'outtime';
|
|
20
|
+
type PUBLISHER = 'publisher';
|
|
16
21
|
}
|
|
17
22
|
|
|
18
23
|
declare class MessageFields {
|
|
@@ -30,4 +35,9 @@ declare class MessageFields {
|
|
|
30
35
|
static INTRANET_IP: MessageFields.INTRANET_IP;
|
|
31
36
|
static ID: MessageFields.ID;
|
|
32
37
|
static TOPIC: MessageFields.TOPIC;
|
|
38
|
+
static MSG: MessageFields.MSG;
|
|
39
|
+
static DATAID: MessageFields.DATAID;
|
|
40
|
+
static USERID: MessageFields.USERID;
|
|
41
|
+
static OUTTIME: MessageFields.OUTTIME;
|
|
42
|
+
static PUBLISHER: MessageFields.PUBLISHER;
|
|
33
43
|
}
|
package/types/message.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
/// <reference path="
|
|
2
|
+
/// <reference path="message-type.d.ts" />
|
|
3
3
|
/// <reference path="message-kind.d.ts" />
|
|
4
4
|
|
|
5
5
|
declare class Message {
|
|
@@ -7,14 +7,14 @@ declare class Message {
|
|
|
7
7
|
type?: MessageType.CONNECT | MessageType.CONNECTACK | MessageType.SEND | MessageType.SENDACK,
|
|
8
8
|
kind?: MessageKind.None | MessageKind.PullRequest | MessageKind.Confirm | MessageKind.Data | MessageKind.Failed
|
|
9
9
|
);
|
|
10
|
-
protocolVersion:
|
|
11
|
-
messageType:
|
|
10
|
+
protocolVersion: 2;
|
|
11
|
+
messageType: MessageType.CONNECT | MessageType.CONNECTACK | MessageType.SEND | MessageType.SENDACK;
|
|
12
12
|
statusCode?: number;
|
|
13
13
|
statusPhrase?: string;
|
|
14
14
|
flag?: number;
|
|
15
15
|
token?: string;
|
|
16
16
|
content?: MessageContent;
|
|
17
|
-
with(key: string, value?: number | bigint | string | Buffer | Date): this;
|
|
17
|
+
with(key: string | MessageKind, value?: number | bigint | string | Buffer | Date): this;
|
|
18
18
|
get buffer(): Buffer;
|
|
19
19
|
static from(buf: Buffer): Message;
|
|
20
20
|
}
|
package/types/message.in.d.ts
CHANGED
|
@@ -751,6 +751,10 @@ declare namespace IncomingMessage {
|
|
|
751
751
|
type TmallAutoTradeModify = Message & { content?: MessageContent & { content?: string | Tmall.Auto.TradeModify } };
|
|
752
752
|
/** {@link Tmall.Auto.TwoWheelsReceiptCreate 天猫汽车 > 天猫二轮车服务工单创建开放} */
|
|
753
753
|
type TmallAutoTwoWheelsReceiptCreate = Message & { content?: MessageContent & { content?: string | Tmall.Auto.TwoWheelsReceiptCreate } };
|
|
754
|
+
/** {@link Tmall.Car.ContractSign 天猫汽车 > 合同签署消息} */
|
|
755
|
+
type TmallCarContractSign = Message & { content?: MessageContent & { content?: string | Tmall.Car.ContractSign } };
|
|
756
|
+
/** {@link Tmall.Car.FinanceMsg 天猫汽车 > 汽车金融消息} */
|
|
757
|
+
type TmallCarFinanceMsg = Message & { content?: MessageContent & { content?: string | Tmall.Car.FinanceMsg } };
|
|
754
758
|
/** {@link Tmall.Channel.ApplyOrderChange 渠道中心API > 申请单变更消息} */
|
|
755
759
|
type TmallChannelApplyOrderChange = Message & { content?: MessageContent & { content?: string | Tmall.Channel.ApplyOrderChange } };
|
|
756
760
|
/** {@link Tmall.Channel.DeliverOrderChange 渠道中心API > 发货单消息变更} */
|
package/types/tmall.d.ts
CHANGED
|
@@ -28,6 +28,25 @@ declare namespace Tmall.Auto {
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/** 天猫汽车 */
|
|
32
|
+
declare namespace Tmall.Car {
|
|
33
|
+
/** 合同签署消息 */
|
|
34
|
+
interface ContractSign {
|
|
35
|
+
/** 合同下载地址,有效期10分钟 */
|
|
36
|
+
contract_url: string;
|
|
37
|
+
/** 订单id */
|
|
38
|
+
order_id: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** 汽车金融消息 */
|
|
42
|
+
interface FinanceMsg {
|
|
43
|
+
/** 订单id */
|
|
44
|
+
order_id: number;
|
|
45
|
+
/** 消息类型: FULL_PURCHASE_FINANCE_CANCEL_MSG_TYPE?,因全款购车导致金融取消 REFUND_FINANCE_CANCEL,因退款导致的金融单关闭 */
|
|
46
|
+
type: string;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
31
50
|
/** 渠道中心API */
|
|
32
51
|
declare namespace Tmall.Channel {
|
|
33
52
|
/** 申请单变更消息 */
|