ts-server-lib 0.0.48
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/TSJournal.d.ts +108 -0
- package/db/TSJournal.js +229 -0
- package/db/TSMongo.d.ts +103 -0
- package/db/TSMongo.js +516 -0
- package/db/TSRQW.d.ts +625 -0
- package/db/TSRQW.js +1204 -0
- package/db/TSRedis.d.ts +530 -0
- package/db/TSRedis.js +1368 -0
- package/db/TSRedisTB.d.ts +80 -0
- package/db/TSRedisTB.js +178 -0
- package/package.json +85 -0
- package/ussd/TSUssdMenu.d.ts +139 -0
- package/ussd/TSUssdMenu.js +368 -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/TSFifo.d.ts +109 -0
- package/utils/TSFifo.js +145 -0
- package/utils/TSFile.d.ts +36 -0
- package/utils/TSFile.js +244 -0
- package/utils/TSHash.d.ts +19 -0
- package/utils/TSHash.js +71 -0
- package/utils/TSRequest.d.ts +248 -0
- package/utils/TSRequest.js +689 -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
- package/utils/object-keys.d.ts +39 -0
- package/utils/object-keys.js +52 -0
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.providersMap = exports.TSUssdProviders = void 0;
|
|
4
|
+
exports.body = body;
|
|
5
|
+
exports.mapArgs = mapArgs;
|
|
6
|
+
exports.purify = purify;
|
|
7
|
+
exports.provider = provider;
|
|
8
|
+
var TSUssdProviders;
|
|
9
|
+
(function (TSUssdProviders) {
|
|
10
|
+
TSUssdProviders["vodacomdrc"] = "vodacom";
|
|
11
|
+
TSUssdProviders["orangedrc"] = "orange";
|
|
12
|
+
TSUssdProviders["airteldrc"] = "airtel";
|
|
13
|
+
TSUssdProviders["africastalking"] = "africastalking";
|
|
14
|
+
})(TSUssdProviders || (exports.TSUssdProviders = TSUssdProviders = {}));
|
|
15
|
+
function body(request) {
|
|
16
|
+
const { headers = {}, body = {}, query = {}, params = {} } = request;
|
|
17
|
+
return { ...headers, ...body, ...query, ...params };
|
|
18
|
+
}
|
|
19
|
+
function mapArgs(args = {}, map = {}) {
|
|
20
|
+
const results = { provider: map.provider };
|
|
21
|
+
for (const p in args) {
|
|
22
|
+
if (Object.hasOwn(args, p) && Object.hasOwn(map, p)) {
|
|
23
|
+
results[String(map[p])] = args[p];
|
|
24
|
+
}
|
|
25
|
+
else if (Object.hasOwn(args, p)) {
|
|
26
|
+
results[p] = args[p];
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return results;
|
|
30
|
+
}
|
|
31
|
+
function purify(text = '') {
|
|
32
|
+
return text ? text.replace(/[^\w\s]/g, '') : '';
|
|
33
|
+
}
|
|
34
|
+
function provider({ headers = {}, body, query }) {
|
|
35
|
+
const h = headers;
|
|
36
|
+
if (body && typeof body === 'object' && 'methodcall' in body) {
|
|
37
|
+
return TSUssdProviders.vodacomdrc;
|
|
38
|
+
}
|
|
39
|
+
else if (h['user-session'] && h['user-msisdn']) {
|
|
40
|
+
return TSUssdProviders.orangedrc;
|
|
41
|
+
}
|
|
42
|
+
else if (query && typeof query === 'object' && 'MBILE_NUMBER' in query) {
|
|
43
|
+
return TSUssdProviders.airteldrc;
|
|
44
|
+
}
|
|
45
|
+
else if (body && typeof body === 'object' && 'text' in body) {
|
|
46
|
+
return TSUssdProviders.africastalking;
|
|
47
|
+
}
|
|
48
|
+
return TSUssdProviders.africastalking;
|
|
49
|
+
}
|
|
50
|
+
exports.providersMap = {
|
|
51
|
+
[TSUssdProviders.africastalking]: {
|
|
52
|
+
africastalking: 'provider',
|
|
53
|
+
sessionId: 'sessionId',
|
|
54
|
+
serviceCode: 'serviceCode',
|
|
55
|
+
phoneNumber: 'phoneNumber',
|
|
56
|
+
networkCode: 'networkCode',
|
|
57
|
+
text: 'message'
|
|
58
|
+
},
|
|
59
|
+
[TSUssdProviders.vodacomdrc]: {
|
|
60
|
+
vodacom: 'provider',
|
|
61
|
+
TransactionId: 'sessionId',
|
|
62
|
+
USSDServiceCode: 'serviceCode',
|
|
63
|
+
MSISDN: 'phoneNumber',
|
|
64
|
+
networkCode: 'networkCode',
|
|
65
|
+
USSDRequestString: 'message'
|
|
66
|
+
},
|
|
67
|
+
[TSUssdProviders.orangedrc]: {
|
|
68
|
+
orange: 'provider',
|
|
69
|
+
'user-session': 'sessionId',
|
|
70
|
+
'user-imsi': 'serviceCode',
|
|
71
|
+
'user-msisdn': 'phoneNumber',
|
|
72
|
+
networkCode: 'networkCode',
|
|
73
|
+
'user-identity': 'message'
|
|
74
|
+
},
|
|
75
|
+
[TSUssdProviders.airteldrc]: {
|
|
76
|
+
airtel: 'provider',
|
|
77
|
+
MBILE_NUMBER: 'phoneNumber',
|
|
78
|
+
USSDServiceCode: 'serviceCode',
|
|
79
|
+
SESSION_ID: 'sessionId',
|
|
80
|
+
INPUT: 'message',
|
|
81
|
+
IMEI: 'networkCode'
|
|
82
|
+
}
|
|
83
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as africastalking from './AfricasTalking';
|
|
2
|
+
import * as airteldrc from './AirtelDRC';
|
|
3
|
+
import * as orangedrc from './OrangeDRC';
|
|
4
|
+
import * as vodacomdrc from './VodacomDRC';
|
|
5
|
+
import { TSUssdProviders } from './_';
|
|
6
|
+
export * from './_';
|
|
7
|
+
export declare const providers: {
|
|
8
|
+
vodacom: typeof vodacomdrc;
|
|
9
|
+
orange: typeof orangedrc;
|
|
10
|
+
airtel: typeof airteldrc;
|
|
11
|
+
africastalking: typeof africastalking;
|
|
12
|
+
};
|
|
13
|
+
export declare const providersAvailable: TSUssdProviders[];
|
|
@@ -0,0 +1,56 @@
|
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
36
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.providersAvailable = exports.providers = void 0;
|
|
40
|
+
const africastalking = __importStar(require("./AfricasTalking"));
|
|
41
|
+
const airteldrc = __importStar(require("./AirtelDRC"));
|
|
42
|
+
const orangedrc = __importStar(require("./OrangeDRC"));
|
|
43
|
+
const vodacomdrc = __importStar(require("./VodacomDRC"));
|
|
44
|
+
const _1 = require("./_");
|
|
45
|
+
__exportStar(require("./_"), exports);
|
|
46
|
+
exports.providers = {
|
|
47
|
+
[_1.TSUssdProviders.vodacomdrc]: vodacomdrc,
|
|
48
|
+
[_1.TSUssdProviders.orangedrc]: orangedrc,
|
|
49
|
+
[_1.TSUssdProviders.airteldrc]: airteldrc,
|
|
50
|
+
[_1.TSUssdProviders.africastalking]: africastalking
|
|
51
|
+
};
|
|
52
|
+
exports.providersAvailable = [
|
|
53
|
+
_1.TSUssdProviders.vodacomdrc,
|
|
54
|
+
_1.TSUssdProviders.orangedrc,
|
|
55
|
+
_1.TSUssdProviders.airteldrc
|
|
56
|
+
];
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TSFifo — O(1) FIFO queue. The canonical replacement for `array.shift()` and `array.splice(0, n)`.
|
|
3
|
+
*
|
|
4
|
+
* ### Why this exists as a primitive
|
|
5
|
+
*
|
|
6
|
+
* `shift()` re-indexes every remaining element, so draining a queue of N with `shift()` is O(N²). The
|
|
7
|
+
* cost arrives at exactly the worst moment: queues are only deep when the system is already stressed, so
|
|
8
|
+
* the drain gets more expensive the more there is to drain. That is a positive feedback loop, not a
|
|
9
|
+
* constant factor — the same shape as the O(N) in-flight scan that was removed from the sports feed's
|
|
10
|
+
* pressure signal for the same reason.
|
|
11
|
+
*
|
|
12
|
+
* ### Why it lives HERE, in ts-server-lib
|
|
13
|
+
*
|
|
14
|
+
* It started in core-service, which was one layer too high: {@link TSRQWPool}'s own task backlog — the
|
|
15
|
+
* FIFTH instance of this defect — could not use it, because core-service depends on ts-server-lib and not
|
|
16
|
+
* the reverse. Copying it down would have produced two implementations of a module whose entire purpose is
|
|
17
|
+
* being the only one. So it sits at the bottom layer and core-service re-exports it, leaving
|
|
18
|
+
* `import { TSFifo } from 'core-service'` working for every service-side caller.
|
|
19
|
+
*
|
|
20
|
+
* It had already been diagnosed and hand-fixed once (`sports-service` `capacity-pump.ts`, head pointer plus
|
|
21
|
+
* periodic compaction, with the reasoning written out) while four other queues kept their own shape:
|
|
22
|
+
*
|
|
23
|
+
* - `feed/amqp/dispatch-admission.ts` — the admission gate's `hotQueue` / `moneyQueue`. Its own doc
|
|
24
|
+
* records `hotQueued` reaching **683** with 24.2 s waits; releasing 683 waiters by `shift()` is ~233 K
|
|
25
|
+
* element moves, on the money path, during a backlog.
|
|
26
|
+
* - `feed/amqp/worker.ts` — `pendingOutcomePublishes`, an uncapped array drained `splice(0, 32)` at a
|
|
27
|
+
* time, so each batch re-indexes everything still queued behind it.
|
|
28
|
+
* - `resolvers/outcomes.ts` — a 64-cap subscriber backlog. Cheap at that size, but it is the site that
|
|
29
|
+
* proves the point: its correct eviction is `'drop-oldest'`, the OPPOSITE of the admission queue's, and
|
|
30
|
+
* that decision was previously an unexplained `queue.shift()` in a callback.
|
|
31
|
+
* - `db/TSRQW.ts` `TSRQWPool.tasks` — the parse-pool backlog, right in the AMQP drain path. Inert while
|
|
32
|
+
* the pool keeps up (`parseQueued ~0` measured) and quadratic exactly when it stops keeping up, which
|
|
33
|
+
* is the moment a super-linear drain hurts most.
|
|
34
|
+
*
|
|
35
|
+
* Five queues, five shapes, one of them correct. That is what a per-site fix always converges to, so the
|
|
36
|
+
* shape is not the interesting part of this module — having exactly one of it is, and naming the overflow
|
|
37
|
+
* policy so the difference between those sites is a type rather than a comment.
|
|
38
|
+
*
|
|
39
|
+
* ALL FIVE now use this class; a sixth hand-rolled queue is the thing to reject in review.
|
|
40
|
+
*
|
|
41
|
+
* ### Design
|
|
42
|
+
*
|
|
43
|
+
* A head index makes `shift` O(1); the consumed prefix is reclaimed in one `splice` once it passes
|
|
44
|
+
* {@link TSFIFO_COMPACT_THRESHOLD}, which keeps the backing array from growing without bound while keeping
|
|
45
|
+
* amortised cost O(1). `maxSize` is optional and, when set, makes overflow an explicit, observable event
|
|
46
|
+
* rather than unbounded memory — a queue with no ceiling is a slower way to run out of RAM.
|
|
47
|
+
*/
|
|
48
|
+
/**
|
|
49
|
+
* Consumed slots tolerated before the backing array is compacted.
|
|
50
|
+
*
|
|
51
|
+
* Compaction is one O(size) `splice` amortised over that many O(1) shifts, so a larger value trades
|
|
52
|
+
* transient memory for fewer memmoves. 1024 matches the value `capacity-pump` arrived at empirically.
|
|
53
|
+
*/
|
|
54
|
+
export declare const TSFIFO_COMPACT_THRESHOLD = 1024;
|
|
55
|
+
export interface TSFifoOptions {
|
|
56
|
+
/**
|
|
57
|
+
* Hard cap on queued items. Omit for unbounded (correct only when an upstream gate already bounds the
|
|
58
|
+
* producer — e.g. a dedup key set, where the ceiling is the key space and not the event rate).
|
|
59
|
+
*/
|
|
60
|
+
maxSize?: number;
|
|
61
|
+
/**
|
|
62
|
+
* WHICH END to sacrifice when `maxSize` is reached. There is no safe default for this question, which is
|
|
63
|
+
* why it is a named option rather than a per-site `if`:
|
|
64
|
+
*
|
|
65
|
+
* - `'reject-new'` (default) — keep the queued items, refuse the arrival. Correct when order carries
|
|
66
|
+
* meaning and the oldest entry is the one that has waited longest for its turn: an admission queue,
|
|
67
|
+
* a heal backlog. `push` returns false and the caller MUST handle it.
|
|
68
|
+
* - `'drop-oldest'` — evict the head to make room. Correct for a LIVE stream, where a late consumer
|
|
69
|
+
* wants current state and a replay of stale values is worse than a gap: an odds subscription.
|
|
70
|
+
*
|
|
71
|
+
* Getting this backwards is silent: both shapes "work", one just serves the wrong data.
|
|
72
|
+
*/
|
|
73
|
+
overflow?: 'reject-new' | 'drop-oldest';
|
|
74
|
+
/** Compaction threshold override — see {@link TSFIFO_COMPACT_THRESHOLD}. */
|
|
75
|
+
compactThreshold?: number;
|
|
76
|
+
}
|
|
77
|
+
export declare class TSFifo<T> {
|
|
78
|
+
private items;
|
|
79
|
+
private head;
|
|
80
|
+
private peak;
|
|
81
|
+
private lost;
|
|
82
|
+
private readonly compactThreshold;
|
|
83
|
+
private readonly maxSize;
|
|
84
|
+
private readonly overflow;
|
|
85
|
+
constructor(opts?: TSFifoOptions);
|
|
86
|
+
/** Items currently queued. */
|
|
87
|
+
get size(): number;
|
|
88
|
+
/** Highest `size` observed since construction — the number a gauge should report. */
|
|
89
|
+
get peakSize(): number;
|
|
90
|
+
/**
|
|
91
|
+
* Items lost to `maxSize` — rejected arrivals under `'reject-new'`, evicted heads under `'drop-oldest'`.
|
|
92
|
+
* Non-zero means the cap is doing something and should be visible: a silent drop is how data loss hides.
|
|
93
|
+
*/
|
|
94
|
+
get dropped(): number;
|
|
95
|
+
/**
|
|
96
|
+
* Append. Returns false only under `'reject-new'` overflow when the queue is full — nothing was
|
|
97
|
+
* enqueued. Under `'drop-oldest'` it always returns true, having evicted the head to make room.
|
|
98
|
+
*/
|
|
99
|
+
push(item: T): boolean;
|
|
100
|
+
/** Remove and return the oldest item, or undefined when empty. O(1). */
|
|
101
|
+
shift(): T | undefined;
|
|
102
|
+
/** Oldest item without removing it, or undefined when empty. */
|
|
103
|
+
peek(): T | undefined;
|
|
104
|
+
/** Drain up to `max` items, oldest first. Amortised O(returned), never O(remaining). */
|
|
105
|
+
drain(max: number): T[];
|
|
106
|
+
/** Discard everything. Use on shutdown/reset paths. */
|
|
107
|
+
clear(): void;
|
|
108
|
+
private compactIfNeeded;
|
|
109
|
+
}
|