ts-server-lib 0.0.17
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/LICENSE +1 -0
- package/README.md +8 -0
- package/db/TSMongo.d.ts +103 -0
- package/db/TSMongo.js +483 -0
- package/db/TSRQW.d.ts +271 -0
- package/db/TSRQW.js +699 -0
- package/db/TSRedis.d.ts +174 -0
- package/db/TSRedis.js +602 -0
- package/package.json +85 -0
- package/ussd/TSUssdMenu.d.ts +139 -0
- package/ussd/TSUssdMenu.js +364 -0
- package/ussd/TSUssdScreen.d.ts +58 -0
- package/ussd/TSUssdScreen.js +218 -0
- package/ussd/index.d.ts +3 -0
- package/ussd/index.js +19 -0
- package/ussd/providers/AfricasTalking.d.ts +3 -0
- package/ussd/providers/AfricasTalking.js +17 -0
- package/ussd/providers/AirtelDRC.d.ts +9 -0
- package/ussd/providers/AirtelDRC.js +31 -0
- package/ussd/providers/OrangeDRC.d.ts +5 -0
- package/ussd/providers/OrangeDRC.js +213 -0
- package/ussd/providers/VodacomDRC.d.ts +9 -0
- package/ussd/providers/VodacomDRC.js +48 -0
- package/ussd/providers/_.d.ts +55 -0
- package/ussd/providers/_.js +83 -0
- package/ussd/providers/index.d.ts +13 -0
- package/ussd/providers/index.js +56 -0
- package/utils/TSFile.d.ts +36 -0
- package/utils/TSFile.js +244 -0
- package/utils/TSHash.d.ts +20 -0
- package/utils/TSHash.js +75 -0
- package/utils/TSRequest.d.ts +39 -0
- package/utils/TSRequest.js +256 -0
- package/utils/TSStub.d.ts +159 -0
- package/utils/TSStub.js +296 -0
- package/utils/abort.d.ts +18 -0
- package/utils/abort.js +97 -0
- package/utils/mime.json +11358 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.TSUssdScreen = void 0;
|
|
7
|
+
const i18n_1 = __importDefault(require("i18n"));
|
|
8
|
+
const TSUssdMenu_1 = require("./TSUssdMenu");
|
|
9
|
+
class TSUssdScreen {
|
|
10
|
+
menu;
|
|
11
|
+
storage;
|
|
12
|
+
strategies = {
|
|
13
|
+
truncate: (data, c, factor) => {
|
|
14
|
+
let parts = [];
|
|
15
|
+
let factors = {};
|
|
16
|
+
let f = 0;
|
|
17
|
+
TSUssdMenu_1.TSUssdMenu.forOwn(data, (i) => {
|
|
18
|
+
const item = i;
|
|
19
|
+
factors = {};
|
|
20
|
+
if (item.name && item.name.length > factor) {
|
|
21
|
+
parts = item.name.split(c.term);
|
|
22
|
+
if (parts.length > 1) {
|
|
23
|
+
f = factor / parts.length;
|
|
24
|
+
if (parts[0].length < f) {
|
|
25
|
+
factors[1] = factor - parts[0].length;
|
|
26
|
+
factors[0] = parts[0].length;
|
|
27
|
+
}
|
|
28
|
+
else if (parts[1].length < f) {
|
|
29
|
+
factors[0] = factor - parts[1].length;
|
|
30
|
+
factors[1] = parts[1].length;
|
|
31
|
+
}
|
|
32
|
+
parts.forEach((v, k) => parts[k] = v.substring(0, factors[k] ?? f));
|
|
33
|
+
item.name = parts.join(c.term);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
return data;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
static nav(command) {
|
|
41
|
+
return TSUssdMenu_1.TSUssdMenu.config.navigation[String(command)];
|
|
42
|
+
}
|
|
43
|
+
static pagerChoice(max = 3, min = 1) {
|
|
44
|
+
return '*\\^\\[' + min + '-' + max + '\\]\\{1\\}\\$';
|
|
45
|
+
}
|
|
46
|
+
constructor(menu, storage) {
|
|
47
|
+
this.menu = menu;
|
|
48
|
+
this.storage = storage;
|
|
49
|
+
}
|
|
50
|
+
render(items) {
|
|
51
|
+
TSUssdMenu_1.TSUssdMenu.forOwn(items, (m) => { const mr = m; if (mr)
|
|
52
|
+
TSUssdMenu_1.TSUssdMenu.forOwn(mr, (v, k) => { if (v !== undefined && k !== undefined)
|
|
53
|
+
this.bind(k, v); }); });
|
|
54
|
+
}
|
|
55
|
+
bind(m, s) {
|
|
56
|
+
const sObj = s;
|
|
57
|
+
if (m === 'start') {
|
|
58
|
+
this.menu.startState({
|
|
59
|
+
run: () => this.menu.con(sObj.next ? i18n_1.default.__(String(m) + '.' + sObj.key, TSUssdMenu_1.TSUssdMenu.config.general || {}) : this.screen(m, sObj)), next: sObj.next ? sObj.next : sObj
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
let options = {};
|
|
64
|
+
if (typeof s === 'function') {
|
|
65
|
+
options.run = s;
|
|
66
|
+
}
|
|
67
|
+
else if (typeof s === 'object' && s !== null && Object.hasOwn(s, 'next')) {
|
|
68
|
+
const navMain = TSUssdScreen.nav('main');
|
|
69
|
+
sObj.next = { [navMain]: TSUssdMenu_1.TSUssdMenu.START_STATE, ...sObj.next };
|
|
70
|
+
options = sObj;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
options.run = () => this.menu.con(this.screen(m, sObj));
|
|
74
|
+
const navMain = TSUssdScreen.nav('main');
|
|
75
|
+
options.next = { [navMain]: TSUssdMenu_1.TSUssdMenu.START_STATE, ...sObj };
|
|
76
|
+
}
|
|
77
|
+
this.menu.state(String(m), options);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
screen(title, items) {
|
|
81
|
+
let context = i18n_1.default.__(String(title), TSUssdMenu_1.TSUssdMenu.config.general || {});
|
|
82
|
+
const data = TSUssdMenu_1.TSUssdMenu.config.general || {};
|
|
83
|
+
TSUssdMenu_1.TSUssdMenu.forOwn(items, (v, k) => {
|
|
84
|
+
if (v != null && !isNaN(Number(k))) {
|
|
85
|
+
context += isNaN(Number(k)) ? '\n' : '\n' + k + data.separator + ' ';
|
|
86
|
+
context += i18n_1.default.__(String(title) + '.' + v, data || {});
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
if (this.menu.current.name !== TSUssdMenu_1.TSUssdMenu.START_STATE) {
|
|
90
|
+
context += '\n' + TSUssdScreen.nav('main');
|
|
91
|
+
context += data.separator + ' ' + i18n_1.default.__('main', data);
|
|
92
|
+
}
|
|
93
|
+
return context;
|
|
94
|
+
}
|
|
95
|
+
list(items, title = '', key = 'name', meta = { back: true, main: true }) {
|
|
96
|
+
let context = title;
|
|
97
|
+
TSUssdMenu_1.TSUssdMenu.forOwn(items, (v, k) => {
|
|
98
|
+
if (typeof v === 'object' && v !== null && key in v) {
|
|
99
|
+
context += isNaN(Number(k)) ? '\n' : '\n' + (parseInt(String(k), 10) + 1) + TSUssdMenu_1.TSUssdMenu.config.general.separator + ' ';
|
|
100
|
+
context += v[key];
|
|
101
|
+
}
|
|
102
|
+
else if (['number', 'string', 'boolean'].includes(typeof v)) {
|
|
103
|
+
context += String(v).indexOf('\n') === -1 ? '\n' + v : String(v);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
console.error(`TSUssdScreen:list[${key} -> ${k}] not mapped with ->`, JSON.stringify(v, null, 2));
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
TSUssdMenu_1.TSUssdMenu.forOwn(meta, (v, k) => { if (k !== undefined)
|
|
110
|
+
context += '\n' + TSUssdScreen.nav(String(k)) + TSUssdMenu_1.TSUssdMenu.config.general.separator + ' ' + i18n_1.default.__(String(k)); });
|
|
111
|
+
return context;
|
|
112
|
+
}
|
|
113
|
+
async getAndSet(key, field) {
|
|
114
|
+
if (!this.storage)
|
|
115
|
+
throw new Error('TSUssdScreen: storage not configured');
|
|
116
|
+
let data = await this.storage.hget(String(this.menu.args.phoneNumber), field);
|
|
117
|
+
if (this.menu.val && this.menu.val.toString().length > 0) {
|
|
118
|
+
if (!data) {
|
|
119
|
+
data = { [key]: this.menu.val };
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
data[key] = this.menu.val;
|
|
123
|
+
}
|
|
124
|
+
await this.storage.hset(String(this.menu.args.phoneNumber), field, data);
|
|
125
|
+
}
|
|
126
|
+
return data;
|
|
127
|
+
}
|
|
128
|
+
async pager(items = [], key, pagerSize) {
|
|
129
|
+
let length = 0;
|
|
130
|
+
const result = await this._pager(items, key, pagerSize);
|
|
131
|
+
TSUssdMenu_1.TSUssdMenu.forOwn(result.data, (i) => { const it = i; length += (it.name?.length ?? 0) || (it.length ?? 0); });
|
|
132
|
+
if (TSUssdMenu_1.TSUssdMenu.config.pager.maxLength < length) {
|
|
133
|
+
TSUssdMenu_1.TSUssdMenu.forOwn(TSUssdMenu_1.TSUssdMenu.config.pager.strategies, (s) => {
|
|
134
|
+
const strat = s;
|
|
135
|
+
if (strat.enabled && strat.type && this.strategies[strat.type]) {
|
|
136
|
+
this.strategies[strat.type](result.data, strat, parseInt((TSUssdMenu_1.TSUssdMenu.config.pager.maxLength / pagerSize).toString(), 10));
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
async _pager(items = [], key, pagerSize) {
|
|
143
|
+
if (!this.storage)
|
|
144
|
+
throw new Error('TSUssdScreen: storage not configured');
|
|
145
|
+
const pagerOptions = (await this.storage.hget(String(this.menu.args.phoneNumber), key + 'Pager') || {}), command = parseInt(this.menu.val, 10), calculatePaging = () => {
|
|
146
|
+
if (pagerSize >= items.length) {
|
|
147
|
+
offset = 0;
|
|
148
|
+
limit = pagerSize;
|
|
149
|
+
}
|
|
150
|
+
else if (command === 7) {
|
|
151
|
+
limit = offset;
|
|
152
|
+
offset -= pagerSize;
|
|
153
|
+
if (offset < 0) {
|
|
154
|
+
offset = 0;
|
|
155
|
+
limit = pagerSize;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
else if (command === 9) {
|
|
159
|
+
offset = limit;
|
|
160
|
+
limit = offset + pagerSize;
|
|
161
|
+
if (limit > items.length) {
|
|
162
|
+
limit = items.length;
|
|
163
|
+
offset = limit - pagerSize;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
let offset = pagerOptions.offset || 0, limit = pagerOptions.limit || (offset + pagerSize);
|
|
168
|
+
calculatePaging();
|
|
169
|
+
let data = items.slice(offset, limit), { length } = data, dataLength = 0;
|
|
170
|
+
TSUssdMenu_1.TSUssdMenu.forOwn(data, (i) => { const it = i; dataLength += it.name ? it.name.length : (it.length ?? 0); });
|
|
171
|
+
if (TSUssdMenu_1.TSUssdMenu.config.pager.maxLength < dataLength) {
|
|
172
|
+
pagerSize = pagerSize - 1;
|
|
173
|
+
offset = pagerOptions.offset || 0;
|
|
174
|
+
limit = pagerOptions.limit || (offset + pagerSize);
|
|
175
|
+
calculatePaging();
|
|
176
|
+
data = items.slice(offset, limit);
|
|
177
|
+
length = data.length;
|
|
178
|
+
}
|
|
179
|
+
await this.storage.hset(String(this.menu.args.phoneNumber), key + 'Pager', { offset: offset, limit: limit });
|
|
180
|
+
if (offset < 1 && items.length > limit) {
|
|
181
|
+
data.push(i18n_1.default.__('\n9 [Next]', TSUssdMenu_1.TSUssdMenu.config.general));
|
|
182
|
+
}
|
|
183
|
+
else if (items.length > limit && offset > 0) {
|
|
184
|
+
data.push(i18n_1.default.__('\n7 [Prev] | 9 [Next]', TSUssdMenu_1.TSUssdMenu.config.general));
|
|
185
|
+
}
|
|
186
|
+
else if (offset > 0) {
|
|
187
|
+
data.push(i18n_1.default.__('\n7 [Prev]', TSUssdMenu_1.TSUssdMenu.config.general));
|
|
188
|
+
}
|
|
189
|
+
return { meta: { command: command, total: items.length, length: length, offset: offset, limit: limit }, data: data };
|
|
190
|
+
}
|
|
191
|
+
async pagerPickAndSet(dataSet = [], field, size = 0) {
|
|
192
|
+
if (!this.storage)
|
|
193
|
+
throw new Error('TSUssdScreen: storage not configured');
|
|
194
|
+
const pagerOptions = (await this.storage.hget(String(this.menu.args.phoneNumber), field + 'Pager') || {}), offset = pagerOptions.offset || 0, limit = pagerOptions.limit || (offset + size), cursor = parseInt(this.menu.val, 10) - 1;
|
|
195
|
+
let data;
|
|
196
|
+
dataSet = size ? dataSet.slice(offset, limit) : dataSet;
|
|
197
|
+
if (size && dataSet.length >= cursor) {
|
|
198
|
+
data = dataSet[cursor];
|
|
199
|
+
}
|
|
200
|
+
if (!size) {
|
|
201
|
+
data = dataSet[cursor + offset];
|
|
202
|
+
}
|
|
203
|
+
await this.storage.hset(String(this.menu.args.phoneNumber), field, data);
|
|
204
|
+
return data;
|
|
205
|
+
}
|
|
206
|
+
checkPick(entity, state) {
|
|
207
|
+
if (!entity && state) {
|
|
208
|
+
this.menu.go(state);
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
else if (!entity) {
|
|
212
|
+
this.menu.end(i18n_1.default.__('invalid.input', { input: this.menu.val }));
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
exports.TSUssdScreen = TSUssdScreen;
|
package/ussd/index.d.ts
ADDED
package/ussd/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./TSUssdMenu"), exports);
|
|
18
|
+
__exportStar(require("./TSUssdScreen"), exports);
|
|
19
|
+
__exportStar(require("./providers/index"), exports);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.response = response;
|
|
4
|
+
exports.request = request;
|
|
5
|
+
exports.text = text;
|
|
6
|
+
const _1 = require("./_");
|
|
7
|
+
function response(text, _rr) {
|
|
8
|
+
return text;
|
|
9
|
+
}
|
|
10
|
+
function request(request, _response) {
|
|
11
|
+
const body = (0, _1.body)(request);
|
|
12
|
+
request.body = (0, _1.mapArgs)(body, _1.providersMap[_1.TSUssdProviders.africastalking]);
|
|
13
|
+
return request.body;
|
|
14
|
+
}
|
|
15
|
+
function text(_prev = '', body) {
|
|
16
|
+
return body.message;
|
|
17
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare function response(text: string, { response }: {
|
|
2
|
+
response: {
|
|
3
|
+
set: (key: string, val: string) => void;
|
|
4
|
+
};
|
|
5
|
+
}): string;
|
|
6
|
+
export declare function request(request: {
|
|
7
|
+
body?: Record<string, unknown>;
|
|
8
|
+
}, response: Record<string, unknown>): Record<string, unknown>;
|
|
9
|
+
export declare function text(prev: string | undefined, body: Record<string, unknown>): string;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.response = response;
|
|
4
|
+
exports.request = request;
|
|
5
|
+
exports.text = text;
|
|
6
|
+
const _1 = require("./_");
|
|
7
|
+
function response(text, { response }) {
|
|
8
|
+
const action = text.startsWith('CON ');
|
|
9
|
+
response.set('Freeflow', action ? 'FC' : 'FB');
|
|
10
|
+
text = text.replace(/CON\s|END\s/g, '');
|
|
11
|
+
return text;
|
|
12
|
+
}
|
|
13
|
+
function request(request, response) {
|
|
14
|
+
const body = (0, _1.body)(request);
|
|
15
|
+
response.type('text/html');
|
|
16
|
+
response.charset = 'UTF-8';
|
|
17
|
+
if (!String(body.MBILE_NUMBER ?? '').startsWith('+')) {
|
|
18
|
+
body.MBILE_NUMBER = '+' + String(body.MBILE_NUMBER);
|
|
19
|
+
}
|
|
20
|
+
if (Object.hasOwn(body, 'INPUT')) {
|
|
21
|
+
body.message = body.INPUT;
|
|
22
|
+
}
|
|
23
|
+
request.body = (0, _1.mapArgs)(body, _1.providersMap[_1.TSUssdProviders.airteldrc]);
|
|
24
|
+
return request.body;
|
|
25
|
+
}
|
|
26
|
+
function text(prev = '', body) {
|
|
27
|
+
if (Object.hasOwn(body, 'message') && body.message !== body.serviceCode) {
|
|
28
|
+
prev += '*' + (0, _1.purify)(String(body.message ?? ''));
|
|
29
|
+
}
|
|
30
|
+
return prev;
|
|
31
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function response(text: string, _rr?: unknown): string;
|
|
2
|
+
export declare function request(request: {
|
|
3
|
+
body?: Record<string, unknown>;
|
|
4
|
+
}, response: Record<string, unknown>): Record<string, unknown>;
|
|
5
|
+
export declare function text(prev: string | undefined, body: Record<string, unknown>): string;
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.response = response;
|
|
4
|
+
exports.request = request;
|
|
5
|
+
exports.text = text;
|
|
6
|
+
const _1 = require("./_");
|
|
7
|
+
class OrangeTextUSSD {
|
|
8
|
+
text;
|
|
9
|
+
description;
|
|
10
|
+
attribute;
|
|
11
|
+
constructor() {
|
|
12
|
+
this.text = '';
|
|
13
|
+
this.description = String(Math.random().toFixed(9));
|
|
14
|
+
this.attribute = { nav: 'default' };
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Append a line text without <br/>
|
|
18
|
+
* @param text
|
|
19
|
+
*/
|
|
20
|
+
appendText(text) {
|
|
21
|
+
this.text += text;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Append a line text with <br/>
|
|
25
|
+
* @param text
|
|
26
|
+
*/
|
|
27
|
+
appendLineText(text) {
|
|
28
|
+
this.text += '<br/>' + text;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* define the text of page
|
|
32
|
+
* @param text
|
|
33
|
+
*/
|
|
34
|
+
setText(text) {
|
|
35
|
+
this.text = text;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* define the value of description of the page
|
|
39
|
+
* @param value
|
|
40
|
+
*/
|
|
41
|
+
setPageDescription(value) {
|
|
42
|
+
this.description = value;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* add a attribute in page header
|
|
46
|
+
* @param key
|
|
47
|
+
* @param value
|
|
48
|
+
*/
|
|
49
|
+
setAttribute(key, value) {
|
|
50
|
+
this.attribute[key] = value;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* remove a key in a header page
|
|
54
|
+
* @param key
|
|
55
|
+
*/
|
|
56
|
+
removeAttribute(key) {
|
|
57
|
+
delete this.attribute[key];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* get the value of the key in the header page
|
|
61
|
+
* @param key
|
|
62
|
+
* @return {*}
|
|
63
|
+
*/
|
|
64
|
+
getAttribute(key) {
|
|
65
|
+
return this.attribute[key];
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* get all attributes values in a object
|
|
69
|
+
* @return {{count: boolean}|*}
|
|
70
|
+
*/
|
|
71
|
+
getAllAttributes() {
|
|
72
|
+
return this.attribute;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* generate a string of key and value
|
|
76
|
+
* @return {string}
|
|
77
|
+
* @private
|
|
78
|
+
*/
|
|
79
|
+
__attributeToString() {
|
|
80
|
+
const attr = this.attribute;
|
|
81
|
+
let result = '';
|
|
82
|
+
for (const key in attr) {
|
|
83
|
+
if (Object.hasOwn(attr, key)) {
|
|
84
|
+
result += key + '=\'' + attr[key] + '\' ';
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Generate the body of page
|
|
91
|
+
* @return {string|*}
|
|
92
|
+
* @protected
|
|
93
|
+
*/
|
|
94
|
+
__toGenerateBody() {
|
|
95
|
+
return this.text;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* generate the page
|
|
99
|
+
* @param body the body of page
|
|
100
|
+
* @return {string}
|
|
101
|
+
* @private
|
|
102
|
+
*/
|
|
103
|
+
__toGeneratePage(body) {
|
|
104
|
+
let page = '<?xml version=\'1.0\' encoding=\'UTF-8\'?>';
|
|
105
|
+
page += '<!DOCTYPE pages SYSTEM \'cellflash-1.3.dtd\'>';
|
|
106
|
+
page += '<pages descr=\'' + this.description + '\'>';
|
|
107
|
+
page += '<page ' + this.__attributeToString() + '>';
|
|
108
|
+
page += body;
|
|
109
|
+
page += '</page></pages>';
|
|
110
|
+
return page;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* generate the form
|
|
114
|
+
* @param text
|
|
115
|
+
* @param action
|
|
116
|
+
* @param name
|
|
117
|
+
* @return {string}
|
|
118
|
+
*/
|
|
119
|
+
form(text = ' ', action = '', name = '_input') {
|
|
120
|
+
return '<form keywords=\'disable\' action=\'' + action + '\'><entry var=\'' + name + '\'><prompt>' + text + '</prompt></entry></form>';
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* generate a anchor
|
|
124
|
+
* @param key
|
|
125
|
+
* @param href
|
|
126
|
+
* @param text
|
|
127
|
+
* @return {string}
|
|
128
|
+
*/
|
|
129
|
+
anchor(text = ' ', href, key) {
|
|
130
|
+
let attr = '';
|
|
131
|
+
if (key) {
|
|
132
|
+
attr += 'key=\'' + key + '\' ';
|
|
133
|
+
}
|
|
134
|
+
if (href) {
|
|
135
|
+
attr += 'href=\'' + href + '\'';
|
|
136
|
+
}
|
|
137
|
+
return '<a ' + attr + '>' + text + '</a>';
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* generate the page
|
|
141
|
+
* @return {string}
|
|
142
|
+
*/
|
|
143
|
+
toXml() {
|
|
144
|
+
return this.__toGeneratePage(this.__toGenerateBody());
|
|
145
|
+
}
|
|
146
|
+
escapeXml(unsafe) {
|
|
147
|
+
return this.unEscapeXml(unsafe).replace(/[&<>'"]/g, c => {
|
|
148
|
+
if (c === '&')
|
|
149
|
+
return '&';
|
|
150
|
+
if (c === '<')
|
|
151
|
+
return '<';
|
|
152
|
+
if (c === '>')
|
|
153
|
+
return '>';
|
|
154
|
+
if (c === '\'')
|
|
155
|
+
return ''';
|
|
156
|
+
if (c === '"')
|
|
157
|
+
return '"';
|
|
158
|
+
return c;
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
unEscapeXml(text) {
|
|
162
|
+
const entities = [
|
|
163
|
+
['amp', '&'], ['apos', '\''], ['#x27', '\''], ['#x2F', '/'],
|
|
164
|
+
['nbsp', ' '], ['#39', '\''], ['#47', '/'], ['lt', '<'], ['gt', '>'], ['quot', '"']
|
|
165
|
+
];
|
|
166
|
+
for (let i = 0, max = entities.length; i < max; ++i) {
|
|
167
|
+
text = text.replace(new RegExp('&' + entities[i][0] + ';', 'g'), entities[i][1]);
|
|
168
|
+
}
|
|
169
|
+
return text;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function response(text, _rr) {
|
|
173
|
+
let action = 'request', oText;
|
|
174
|
+
const otu = new OrangeTextUSSD();
|
|
175
|
+
if (text.startsWith('END ')) {
|
|
176
|
+
otu.setAttribute('nav', 'end');
|
|
177
|
+
action = 'end';
|
|
178
|
+
}
|
|
179
|
+
oText = otu.escapeXml(text.replace(/CON\s|END\s/g, '')).replace(/\n/g, '<br />');
|
|
180
|
+
otu.setAttribute('volatile', true);
|
|
181
|
+
otu.setAttribute('menutext', 'notext');
|
|
182
|
+
otu.setAttribute('backtext', 'notext');
|
|
183
|
+
if (action !== 'end') {
|
|
184
|
+
oText += otu.form();
|
|
185
|
+
}
|
|
186
|
+
if (oText.match(/#0/g)) {
|
|
187
|
+
// outputText = outputText.replace('#0)', otu.anchor('#0)', '/?_input=#0'));
|
|
188
|
+
}
|
|
189
|
+
if (oText.match(/#1/g)) {
|
|
190
|
+
// outputText = outputText.replace('#1)', otu.anchor('#1)', '/?_input=#1'));
|
|
191
|
+
}
|
|
192
|
+
otu.setText(oText);
|
|
193
|
+
return otu.toXml();
|
|
194
|
+
}
|
|
195
|
+
function request(request, response) {
|
|
196
|
+
const body = (0, _1.body)(request);
|
|
197
|
+
response.type('application/xml');
|
|
198
|
+
response.charset = 'UTF-8';
|
|
199
|
+
if (!String(body['user-msisdn'] ?? '').startsWith('+')) {
|
|
200
|
+
body['user-msisdn'] = '+' + body['user-msisdn'];
|
|
201
|
+
}
|
|
202
|
+
if (Object.hasOwn(body, '_input')) {
|
|
203
|
+
body.message = body._input;
|
|
204
|
+
}
|
|
205
|
+
request.body = (0, _1.mapArgs)(body, _1.providersMap[_1.TSUssdProviders.orangedrc]);
|
|
206
|
+
return request.body;
|
|
207
|
+
}
|
|
208
|
+
function text(prev = '', body) {
|
|
209
|
+
if (Object.hasOwn(body, 'message')) {
|
|
210
|
+
prev += '*' + (0, _1.purify)(String(body.message ?? ''));
|
|
211
|
+
}
|
|
212
|
+
return prev;
|
|
213
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare function response(text: string, { request: { body } }: {
|
|
2
|
+
request: {
|
|
3
|
+
body: Record<string, unknown>;
|
|
4
|
+
};
|
|
5
|
+
}): string;
|
|
6
|
+
export declare function request(request: {
|
|
7
|
+
body?: Record<string, unknown>;
|
|
8
|
+
}, response: Record<string, unknown>): Record<string, unknown>;
|
|
9
|
+
export declare function text(prev: string | undefined, body: Record<string, unknown>): string;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.response = response;
|
|
4
|
+
exports.request = request;
|
|
5
|
+
exports.text = text;
|
|
6
|
+
const _1 = require("./_");
|
|
7
|
+
function response(text, { request: { body } }) {
|
|
8
|
+
let action = 'request';
|
|
9
|
+
if (text.startsWith('END ')) {
|
|
10
|
+
action = 'end';
|
|
11
|
+
}
|
|
12
|
+
text = text.replace(/CON\s|END\s/g, '');
|
|
13
|
+
text = '<?xml version="1.0" encoding="UTF-8" ?>' +
|
|
14
|
+
'<methodResponse><params><param><value><struct>' +
|
|
15
|
+
'<member><name>USSDResponseString</name><value><string>' + text + '</string></value></member>' +
|
|
16
|
+
'<member><name>action</name><value><string>' + action + '</string></value></member>' +
|
|
17
|
+
'<member><name>TransactionTime</name><value><dateTime.iso8601>' + body.transactionTime + '</dateTime.iso8601></value></member>' +
|
|
18
|
+
'<member><name>TransactionId</name><value><string>' + body.sessionId + '</string></value></member>' +
|
|
19
|
+
'</struct></value></param></params></methodResponse>';
|
|
20
|
+
return text;
|
|
21
|
+
}
|
|
22
|
+
function request(request, response) {
|
|
23
|
+
const body = (0, _1.body)(request);
|
|
24
|
+
response.type('text/xml');
|
|
25
|
+
response.charset = 'UTF-8';
|
|
26
|
+
const transTime = body.TransactionTime;
|
|
27
|
+
body.transactionTime = transTime?.['datetime.iso8601']?.[0];
|
|
28
|
+
if (!String(body.MSISDN ?? '').startsWith('+')) {
|
|
29
|
+
body.MSISDN = '+' + String(body.MSISDN);
|
|
30
|
+
}
|
|
31
|
+
delete body.TransactionTime;
|
|
32
|
+
request.body = (0, _1.mapArgs)(body, {
|
|
33
|
+
vodacom: 'provider',
|
|
34
|
+
TransactionId: 'sessionId',
|
|
35
|
+
USSDServiceCode: 'serviceCode',
|
|
36
|
+
MSISDN: 'phoneNumber',
|
|
37
|
+
networkCode: 'networkCode',
|
|
38
|
+
USSDRequestString: 'message'
|
|
39
|
+
});
|
|
40
|
+
request.body = (0, _1.mapArgs)(body, _1.providersMap[_1.TSUssdProviders.vodacomdrc]);
|
|
41
|
+
return request.body;
|
|
42
|
+
}
|
|
43
|
+
function text(prev = '', body) {
|
|
44
|
+
if (!/(null|fecofa)/i.test(String(body.message ?? ''))) {
|
|
45
|
+
prev += '*' + (0, _1.purify)(String(body.message ?? ''));
|
|
46
|
+
}
|
|
47
|
+
return prev;
|
|
48
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export declare enum TSUssdProviders {
|
|
2
|
+
vodacomdrc = "vodacom",
|
|
3
|
+
orangedrc = "orange",
|
|
4
|
+
airteldrc = "airtel",
|
|
5
|
+
africastalking = "africastalking"
|
|
6
|
+
}
|
|
7
|
+
export declare function body(request: {
|
|
8
|
+
headers?: Record<string, unknown>;
|
|
9
|
+
body?: Record<string, unknown>;
|
|
10
|
+
query?: Record<string, unknown>;
|
|
11
|
+
params?: Record<string, unknown>;
|
|
12
|
+
}): {
|
|
13
|
+
[x: string]: unknown;
|
|
14
|
+
};
|
|
15
|
+
export declare function mapArgs(args?: Record<string, unknown>, map?: Record<string, unknown>): Record<string, unknown>;
|
|
16
|
+
export declare function purify(text?: string): string;
|
|
17
|
+
export declare function provider({ headers, body, query }: {
|
|
18
|
+
headers?: Record<string, unknown>;
|
|
19
|
+
body?: Record<string, unknown>;
|
|
20
|
+
query?: Record<string, unknown>;
|
|
21
|
+
}): TSUssdProviders;
|
|
22
|
+
export declare const providersMap: {
|
|
23
|
+
africastalking: {
|
|
24
|
+
africastalking: string;
|
|
25
|
+
sessionId: string;
|
|
26
|
+
serviceCode: string;
|
|
27
|
+
phoneNumber: string;
|
|
28
|
+
networkCode: string;
|
|
29
|
+
text: string;
|
|
30
|
+
};
|
|
31
|
+
vodacom: {
|
|
32
|
+
vodacom: string;
|
|
33
|
+
TransactionId: string;
|
|
34
|
+
USSDServiceCode: string;
|
|
35
|
+
MSISDN: string;
|
|
36
|
+
networkCode: string;
|
|
37
|
+
USSDRequestString: string;
|
|
38
|
+
};
|
|
39
|
+
orange: {
|
|
40
|
+
orange: string;
|
|
41
|
+
'user-session': string;
|
|
42
|
+
'user-imsi': string;
|
|
43
|
+
'user-msisdn': string;
|
|
44
|
+
networkCode: string;
|
|
45
|
+
'user-identity': string;
|
|
46
|
+
};
|
|
47
|
+
airtel: {
|
|
48
|
+
airtel: string;
|
|
49
|
+
MBILE_NUMBER: string;
|
|
50
|
+
USSDServiceCode: string;
|
|
51
|
+
SESSION_ID: string;
|
|
52
|
+
INPUT: string;
|
|
53
|
+
IMEI: string;
|
|
54
|
+
};
|
|
55
|
+
};
|