@ingestkorea/client-sens 1.4.0 → 1.4.2
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/.github/pull_request_template.md +14 -0
- package/README.md +14 -5
- package/dist-cjs/SensClient.js +2 -1
- package/dist-cjs/commands/SendSMSCommand.js +29 -14
- package/dist-cjs/middleware/index.js +2 -1
- package/dist-cjs/middleware/metadata-ingestkorea.js +28 -0
- package/dist-cjs/middleware/{signer.js → signer-ncp.js} +5 -4
- package/dist-es/SensClient.js +3 -2
- package/dist-es/commands/SendSMSCommand.js +35 -20
- package/dist-es/middleware/index.js +2 -1
- package/dist-es/middleware/metadata-ingestkorea.js +19 -0
- package/dist-es/middleware/{signer.js → signer-ncp.js} +3 -2
- package/dist-types/middleware/index.d.ts +2 -1
- package/dist-types/middleware/metadata-ingestkorea.d.ts +3 -0
- package/dist-types/middleware/signer-ncp.d.ts +3 -0
- package/package.json +1 -1
- package/dist-types/middleware/signer.d.ts +0 -3
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
### Issue
|
|
2
|
+
Issue number, if available, prefixed with "#"
|
|
3
|
+
|
|
4
|
+
### Description
|
|
5
|
+
What does this implement/fix? Explain your changes.
|
|
6
|
+
|
|
7
|
+
### Testing
|
|
8
|
+
How was this change tested?
|
|
9
|
+
|
|
10
|
+
### Additional context
|
|
11
|
+
Add any other context about the PR here.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
|
package/README.md
CHANGED
|
@@ -61,10 +61,16 @@ const client = new SensClient({
|
|
|
61
61
|
serviceId: {
|
|
62
62
|
sms: 'ncp:sms:kr:123456789xxx:your-service-name', // optional
|
|
63
63
|
kakao: 'ncp:kkobizmsg:kr:9876xxx:your-service-name' // optional
|
|
64
|
-
// at least one serviceId required
|
|
65
|
-
// if you call send operation without serviceId, sdk throw error
|
|
66
64
|
}
|
|
67
65
|
});
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* accessKey, secretKey: https://www.ncloud.com/mypage/manage/authkey
|
|
69
|
+
* serviceId: https://console.ncloud.com/sens/project
|
|
70
|
+
*
|
|
71
|
+
* at least one serviceId required
|
|
72
|
+
* if you call send operation without serviceId, sdk throw error
|
|
73
|
+
*/
|
|
68
74
|
```
|
|
69
75
|
|
|
70
76
|
#### SendAlimtalk
|
|
@@ -83,14 +89,17 @@ let command = new SendAlimtalkCommand(params);
|
|
|
83
89
|
```ts
|
|
84
90
|
/**
|
|
85
91
|
* Automatically set message type('SMS' | 'LMS') according to content-length(euc-kr)
|
|
86
|
-
* SMS: max
|
|
92
|
+
* SMS: max 90bytes
|
|
87
93
|
* LMS: max 2000bytes
|
|
88
94
|
*/
|
|
89
95
|
let params: SendSMSCommandInput = {
|
|
90
96
|
from: '01012345678',
|
|
91
|
-
content:
|
|
97
|
+
content: DEFAULT_CONTENT,
|
|
92
98
|
messages: [
|
|
93
|
-
{
|
|
99
|
+
{
|
|
100
|
+
to: '01087654321',
|
|
101
|
+
content: OPTIONAL_CONTENT // optional // this OPTIONAL_CONTENT override above DEFAULT_CONTENT
|
|
102
|
+
}
|
|
94
103
|
]
|
|
95
104
|
};
|
|
96
105
|
let command = new SendSMSCommand(params);
|
package/dist-cjs/SensClient.js
CHANGED
|
@@ -30,7 +30,8 @@ class SensClient {
|
|
|
30
30
|
return __awaiter(this, void 0, void 0, function* () {
|
|
31
31
|
let input = command.input;
|
|
32
32
|
let request = yield command.serialize(input, this.config);
|
|
33
|
-
request = yield (0, middleware_1.
|
|
33
|
+
request = yield (0, middleware_1.middlewareNcpSigner)(request, this.config);
|
|
34
|
+
request = yield (0, middleware_1.middlewareIngestkoreaMetadata)(request, this.config);
|
|
34
35
|
let { response } = yield this.httpHandler.handle(request);
|
|
35
36
|
let output = yield command.deserialize(response);
|
|
36
37
|
return output;
|
|
@@ -18,11 +18,10 @@ const util_error_handler_1 = require("@ingestkorea/util-error-handler");
|
|
|
18
18
|
class SendSMSCommand extends models_1.SensCommand {
|
|
19
19
|
constructor(input) {
|
|
20
20
|
super(input);
|
|
21
|
-
const content =
|
|
22
|
-
const messageType =
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}) });
|
|
21
|
+
const content = trimText(input.content);
|
|
22
|
+
const { messages, messageType: childMessageType } = resolveInputMessages(input.messages);
|
|
23
|
+
const messageType = childMessageType == 'LMS' ? childMessageType : checkMessageType(content);
|
|
24
|
+
this.input = Object.assign(Object.assign({}, input), { from: prettyPhoneNum(input.from), content: content, type: messageType, messages: messages });
|
|
26
25
|
}
|
|
27
26
|
;
|
|
28
27
|
serialize(input, config) {
|
|
@@ -46,25 +45,41 @@ class SendSMSCommand extends models_1.SensCommand {
|
|
|
46
45
|
}
|
|
47
46
|
exports.SendSMSCommand = SendSMSCommand;
|
|
48
47
|
;
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
const euckrByte = input.split('').reduce((acc, text) => {
|
|
48
|
+
const trimText = (input) => input.trim();
|
|
49
|
+
const prettyPhoneNum = (input) => input.replace(/\-/gi, "");
|
|
50
|
+
const getTextBytes = (input) => {
|
|
51
|
+
return input.split('').reduce((acc, text) => {
|
|
54
52
|
let byte = Buffer.from(text).length;
|
|
55
53
|
let modulo = byte % 3;
|
|
56
54
|
modulo ? acc += 1 : acc += 2;
|
|
57
55
|
return acc;
|
|
58
56
|
}, 0);
|
|
59
|
-
|
|
57
|
+
};
|
|
58
|
+
const checkMessageType = (input) => {
|
|
59
|
+
const SMS_MAX = 90;
|
|
60
|
+
const LMS_MAX = 2000;
|
|
61
|
+
const euckrBytes = getTextBytes(input);
|
|
62
|
+
if (!euckrBytes)
|
|
60
63
|
throw new util_error_handler_1.IngestkoreaError({
|
|
61
64
|
code: 400, type: 'Bad Request',
|
|
62
65
|
message: 'Invalid Request', description: `Please check input message`
|
|
63
66
|
});
|
|
64
|
-
if (
|
|
67
|
+
if (euckrBytes > LMS_MAX)
|
|
65
68
|
throw new util_error_handler_1.IngestkoreaError({
|
|
66
69
|
code: 400, type: 'Bad Request',
|
|
67
|
-
message: 'Invalid Request', description: `Maximum message length is ${
|
|
70
|
+
message: 'Invalid Request', description: `Maximum message length is ${LMS_MAX}bytes`
|
|
68
71
|
});
|
|
69
|
-
return
|
|
72
|
+
return euckrBytes > SMS_MAX ? 'LMS' : 'SMS';
|
|
73
|
+
};
|
|
74
|
+
const resolveInputMessages = (messages) => {
|
|
75
|
+
let resolvedMessageType = 'SMS';
|
|
76
|
+
let resolvedMessages = messages.map(message => {
|
|
77
|
+
const resolvedContent = message.content != undefined ? trimText(message.content) : '';
|
|
78
|
+
const resolvedSubject = message.subject != undefined ? trimText(message.subject) : '';
|
|
79
|
+
const messageType = !!resolvedContent != false ? checkMessageType(resolvedContent) : 'SMS';
|
|
80
|
+
if (messageType === 'LMS')
|
|
81
|
+
resolvedMessageType = messageType;
|
|
82
|
+
return Object.assign(Object.assign({ to: prettyPhoneNum(message.to) }, (!!resolvedContent != false && { content: resolvedContent })), (!!resolvedSubject != false && messageType === 'LMS' && { subject: resolvedSubject }));
|
|
83
|
+
});
|
|
84
|
+
return { messages: resolvedMessages, messageType: resolvedMessageType };
|
|
70
85
|
};
|
|
@@ -14,4 +14,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./signer"), exports);
|
|
17
|
+
__exportStar(require("./signer-ncp"), exports);
|
|
18
|
+
__exportStar(require("./metadata-ingestkorea"), exports);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.middlewareIngestkoreaMetadata = void 0;
|
|
13
|
+
const middlewareIngestkoreaMetadata = (request, config) => __awaiter(void 0, void 0, void 0, function* () {
|
|
14
|
+
const { longDate } = yield convertFormatDate(request.headers['x-ncp-apigw-timestamp']);
|
|
15
|
+
request.headers = Object.assign(Object.assign({}, request.headers), { ['x-ingestkorea-date']: longDate, ['x-ingestkorea-user-agent']: '@ingestkorea/client-sens/1.4.x' });
|
|
16
|
+
return request;
|
|
17
|
+
});
|
|
18
|
+
exports.middlewareIngestkoreaMetadata = middlewareIngestkoreaMetadata;
|
|
19
|
+
/**
|
|
20
|
+
* @param input milliseconds
|
|
21
|
+
*/
|
|
22
|
+
const convertFormatDate = (input) => __awaiter(void 0, void 0, void 0, function* () {
|
|
23
|
+
let milliseconds = input ? Number(input) : new Date().getTime();
|
|
24
|
+
let iso8601 = new Date(milliseconds).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
25
|
+
let longDate = iso8601.replace(/[\-:]/g, "");
|
|
26
|
+
let shortDate = longDate.slice(0, 8);
|
|
27
|
+
return { longDate, shortDate };
|
|
28
|
+
});
|
|
@@ -9,12 +9,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.
|
|
12
|
+
exports.middlewareNcpSigner = void 0;
|
|
13
13
|
const crypto_1 = require("crypto");
|
|
14
|
-
const
|
|
14
|
+
const util_http_handler_1 = require("@ingestkorea/util-http-handler");
|
|
15
|
+
const middlewareNcpSigner = (request, config) => __awaiter(void 0, void 0, void 0, function* () {
|
|
15
16
|
const { accessKey, secretKey } = config.credentials;
|
|
16
17
|
const method = request.method;
|
|
17
|
-
const queryString =
|
|
18
|
+
const queryString = (0, util_http_handler_1.buildQueryString)(request.query);
|
|
18
19
|
const path = queryString ? `${request.path}?${queryString}` : request.path;
|
|
19
20
|
const space = " ";
|
|
20
21
|
const newLine = "\n";
|
|
@@ -28,4 +29,4 @@ const middlewareSigner = (request, config) => __awaiter(void 0, void 0, void 0,
|
|
|
28
29
|
request.headers = Object.assign(Object.assign({}, request.headers), { ['x-ncp-iam-access-key']: accessKey, ['x-ncp-apigw-timestamp']: timestamp, ['x-ncp-apigw-signature-v2']: signature });
|
|
29
30
|
return request;
|
|
30
31
|
});
|
|
31
|
-
exports.
|
|
32
|
+
exports.middlewareNcpSigner = middlewareNcpSigner;
|
package/dist-es/SensClient.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NodeHttpHandler } from '@ingestkorea/util-http-handler';
|
|
2
2
|
import { IngestkoreaError } from '@ingestkorea/util-error-handler';
|
|
3
|
-
import {
|
|
3
|
+
import { middlewareNcpSigner, middlewareIngestkoreaMetadata } from './middleware';
|
|
4
4
|
;
|
|
5
5
|
;
|
|
6
6
|
export class SensClient {
|
|
@@ -17,7 +17,8 @@ export class SensClient {
|
|
|
17
17
|
async send(command) {
|
|
18
18
|
let input = command.input;
|
|
19
19
|
let request = await command.serialize(input, this.config);
|
|
20
|
-
request = await
|
|
20
|
+
request = await middlewareNcpSigner(request, this.config);
|
|
21
|
+
request = await middlewareIngestkoreaMetadata(request, this.config);
|
|
21
22
|
let { response } = await this.httpHandler.handle(request);
|
|
22
23
|
let output = await command.deserialize(response);
|
|
23
24
|
return output;
|
|
@@ -6,20 +6,15 @@ import { IngestkoreaError } from '@ingestkorea/util-error-handler';
|
|
|
6
6
|
export class SendSMSCommand extends SensCommand {
|
|
7
7
|
constructor(input) {
|
|
8
8
|
super(input);
|
|
9
|
-
const content =
|
|
10
|
-
const messageType =
|
|
9
|
+
const content = trimText(input.content);
|
|
10
|
+
const { messages, messageType: childMessageType } = resolveInputMessages(input.messages);
|
|
11
|
+
const messageType = childMessageType == 'LMS' ? childMessageType : checkMessageType(content);
|
|
11
12
|
this.input = {
|
|
12
13
|
...input,
|
|
13
|
-
from:
|
|
14
|
+
from: prettyPhoneNum(input.from),
|
|
14
15
|
content: content,
|
|
15
|
-
type:
|
|
16
|
-
messages:
|
|
17
|
-
return {
|
|
18
|
-
to: phoneNumPretty(message.to),
|
|
19
|
-
...(message.content != undefined && { content: textTrimming(message.content) }),
|
|
20
|
-
...(message.subject != undefined && messageType === 'LMS' && { subject: textTrimming(message.subject) }),
|
|
21
|
-
};
|
|
22
|
-
})
|
|
16
|
+
type: messageType,
|
|
17
|
+
messages: messages
|
|
23
18
|
};
|
|
24
19
|
}
|
|
25
20
|
;
|
|
@@ -39,25 +34,45 @@ export class SendSMSCommand extends SensCommand {
|
|
|
39
34
|
;
|
|
40
35
|
}
|
|
41
36
|
;
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
const euckrByte = input.split('').reduce((acc, text) => {
|
|
37
|
+
const trimText = (input) => input.trim();
|
|
38
|
+
const prettyPhoneNum = (input) => input.replace(/\-/gi, "");
|
|
39
|
+
const getTextBytes = (input) => {
|
|
40
|
+
return input.split('').reduce((acc, text) => {
|
|
47
41
|
let byte = Buffer.from(text).length;
|
|
48
42
|
let modulo = byte % 3;
|
|
49
43
|
modulo ? acc += 1 : acc += 2;
|
|
50
44
|
return acc;
|
|
51
45
|
}, 0);
|
|
52
|
-
|
|
46
|
+
};
|
|
47
|
+
const checkMessageType = (input) => {
|
|
48
|
+
const SMS_MAX = 90;
|
|
49
|
+
const LMS_MAX = 2000;
|
|
50
|
+
const euckrBytes = getTextBytes(input);
|
|
51
|
+
if (!euckrBytes)
|
|
53
52
|
throw new IngestkoreaError({
|
|
54
53
|
code: 400, type: 'Bad Request',
|
|
55
54
|
message: 'Invalid Request', description: `Please check input message`
|
|
56
55
|
});
|
|
57
|
-
if (
|
|
56
|
+
if (euckrBytes > LMS_MAX)
|
|
58
57
|
throw new IngestkoreaError({
|
|
59
58
|
code: 400, type: 'Bad Request',
|
|
60
|
-
message: 'Invalid Request', description: `Maximum message length is ${
|
|
59
|
+
message: 'Invalid Request', description: `Maximum message length is ${LMS_MAX}bytes`
|
|
61
60
|
});
|
|
62
|
-
return
|
|
61
|
+
return euckrBytes > SMS_MAX ? 'LMS' : 'SMS';
|
|
62
|
+
};
|
|
63
|
+
const resolveInputMessages = (messages) => {
|
|
64
|
+
let resolvedMessageType = 'SMS';
|
|
65
|
+
let resolvedMessages = messages.map(message => {
|
|
66
|
+
const resolvedContent = message.content != undefined ? trimText(message.content) : '';
|
|
67
|
+
const resolvedSubject = message.subject != undefined ? trimText(message.subject) : '';
|
|
68
|
+
const messageType = !!resolvedContent != false ? checkMessageType(resolvedContent) : 'SMS';
|
|
69
|
+
if (messageType === 'LMS')
|
|
70
|
+
resolvedMessageType = messageType;
|
|
71
|
+
return {
|
|
72
|
+
to: prettyPhoneNum(message.to),
|
|
73
|
+
...(!!resolvedContent != false && { content: resolvedContent }),
|
|
74
|
+
...(!!resolvedSubject != false && messageType === 'LMS' && { subject: resolvedSubject }),
|
|
75
|
+
};
|
|
76
|
+
});
|
|
77
|
+
return { messages: resolvedMessages, messageType: resolvedMessageType };
|
|
63
78
|
};
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export * from './signer';
|
|
1
|
+
export * from './signer-ncp';
|
|
2
|
+
export * from './metadata-ingestkorea';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export const middlewareIngestkoreaMetadata = async (request, config) => {
|
|
2
|
+
const { longDate } = await convertFormatDate(request.headers['x-ncp-apigw-timestamp']);
|
|
3
|
+
request.headers = {
|
|
4
|
+
...request.headers,
|
|
5
|
+
['x-ingestkorea-date']: longDate,
|
|
6
|
+
['x-ingestkorea-user-agent']: '@ingestkorea/client-sens/1.4.x'
|
|
7
|
+
};
|
|
8
|
+
return request;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* @param input milliseconds
|
|
12
|
+
*/
|
|
13
|
+
const convertFormatDate = async (input) => {
|
|
14
|
+
let milliseconds = input ? Number(input) : new Date().getTime();
|
|
15
|
+
let iso8601 = new Date(milliseconds).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
16
|
+
let longDate = iso8601.replace(/[\-:]/g, "");
|
|
17
|
+
let shortDate = longDate.slice(0, 8);
|
|
18
|
+
return { longDate, shortDate };
|
|
19
|
+
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { createHmac } from 'crypto';
|
|
2
|
-
|
|
2
|
+
import { buildQueryString } from '@ingestkorea/util-http-handler';
|
|
3
|
+
export const middlewareNcpSigner = async (request, config) => {
|
|
3
4
|
const { accessKey, secretKey } = config.credentials;
|
|
4
5
|
const method = request.method;
|
|
5
|
-
const queryString =
|
|
6
|
+
const queryString = buildQueryString(request.query);
|
|
6
7
|
const path = queryString ? `${request.path}?${queryString}` : request.path;
|
|
7
8
|
const space = " ";
|
|
8
9
|
const newLine = "\n";
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export * from './signer';
|
|
1
|
+
export * from './signer-ncp';
|
|
2
|
+
export * from './metadata-ingestkorea';
|
package/package.json
CHANGED