@bitblit/ratchet-common 4.0.80-alpha
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/dist/cjs/2d/line-2d.js +2 -0
- package/dist/cjs/2d/plane-2d.js +2 -0
- package/dist/cjs/2d/point-2d.js +2 -0
- package/dist/cjs/2d/poly-line-2d.js +2 -0
- package/dist/cjs/2d/ratchet-2d.js +250 -0
- package/dist/cjs/build/build-information.js +2 -0
- package/dist/cjs/build/ratchet-common-info.js +18 -0
- package/dist/cjs/histogram/histogram-entry.js +2 -0
- package/dist/cjs/histogram/histogram.js +54 -0
- package/dist/cjs/index.js +74 -0
- package/dist/cjs/jwt/common-jwt-token.js +2 -0
- package/dist/cjs/jwt/expired-jwt-handling.js +9 -0
- package/dist/cjs/jwt/jwt-ratchet-like.js +2 -0
- package/dist/cjs/jwt/jwt-ratchet.js +164 -0
- package/dist/cjs/jwt/jwt-token-base.js +2 -0
- package/dist/cjs/lang/array-ratchet.js +87 -0
- package/dist/cjs/lang/base64-ratchet.js +49 -0
- package/dist/cjs/lang/boolean-ratchet.js +49 -0
- package/dist/cjs/lang/composite-last-success-provider.js +28 -0
- package/dist/cjs/lang/date-ratchet.js +33 -0
- package/dist/cjs/lang/duration-ratchet.js +46 -0
- package/dist/cjs/lang/enum-ratchet.js +34 -0
- package/dist/cjs/lang/error-ratchet.js +49 -0
- package/dist/cjs/lang/expiring-object.js +68 -0
- package/dist/cjs/lang/geolocation-ratchet.js +267 -0
- package/dist/cjs/lang/global-ratchet.js +48 -0
- package/dist/cjs/lang/key-value.js +6 -0
- package/dist/cjs/lang/last-success-provider.js +2 -0
- package/dist/cjs/lang/map-ratchet.js +168 -0
- package/dist/cjs/lang/no.js +8 -0
- package/dist/cjs/lang/number-ratchet.js +156 -0
- package/dist/cjs/lang/parsed-url.js +2 -0
- package/dist/cjs/lang/promise-ratchet.js +142 -0
- package/dist/cjs/lang/require-ratchet.js +60 -0
- package/dist/cjs/lang/stop-watch.js +117 -0
- package/dist/cjs/lang/string-ratchet.js +195 -0
- package/dist/cjs/lang/time-zone-ratchet.js +80 -0
- package/dist/cjs/lang/timeout-token.js +19 -0
- package/dist/cjs/lang/transform-ratchet.js +70 -0
- package/dist/cjs/logger/classic-single-line-log-message-formatter.js +18 -0
- package/dist/cjs/logger/log-message-builder.js +51 -0
- package/dist/cjs/logger/log-message-format-type.js +9 -0
- package/dist/cjs/logger/log-message-formatter.js +2 -0
- package/dist/cjs/logger/log-message-processor.js +2 -0
- package/dist/cjs/logger/log-message.js +2 -0
- package/dist/cjs/logger/log-snapshot.js +2 -0
- package/dist/cjs/logger/logger-instance.js +207 -0
- package/dist/cjs/logger/logger-level-name.js +12 -0
- package/dist/cjs/logger/logger-meta.js +2 -0
- package/dist/cjs/logger/logger-options.js +2 -0
- package/dist/cjs/logger/logger-output-function.js +9 -0
- package/dist/cjs/logger/logger-ring-buffer.js +76 -0
- package/dist/cjs/logger/logger-util.js +49 -0
- package/dist/cjs/logger/logger.js +139 -0
- package/dist/cjs/logger/none-log-message-formatter.js +9 -0
- package/dist/cjs/logger/structured-json-log-message-formatter.js +24 -0
- package/dist/cjs/network/browser-local-ip-provider.js +25 -0
- package/dist/cjs/network/fixed-local-ip-provider.js +12 -0
- package/dist/cjs/network/local-ip-provider.js +2 -0
- package/dist/cjs/network/network-ratchet.js +106 -0
- package/dist/cjs/stream/buffer-writable.js +20 -0
- package/dist/cjs/stream/stream-ratchet.js +72 -0
- package/dist/cjs/stream/string-writable.js +18 -0
- package/dist/cjs/third-party/google/google-recaptcha-ratchet.js +33 -0
- package/dist/cjs/third-party/twilio/twilio-ratchet.js +75 -0
- package/dist/cjs/transform/built-in-transforms.js +195 -0
- package/dist/cjs/transform/transform-rule.js +2 -0
- package/dist/cjs/tx/transaction-configuration.js +2 -0
- package/dist/cjs/tx/transaction-final-state.js +9 -0
- package/dist/cjs/tx/transaction-ratchet.js +80 -0
- package/dist/cjs/tx/transaction-result.js +2 -0
- package/dist/cjs/tx/transaction-step.js +2 -0
- package/dist/es/2d/line-2d.js +1 -0
- package/dist/es/2d/plane-2d.js +1 -0
- package/dist/es/2d/point-2d.js +1 -0
- package/dist/es/2d/poly-line-2d.js +1 -0
- package/dist/es/2d/ratchet-2d.js +245 -0
- package/dist/es/build/build-information.js +1 -0
- package/dist/es/build/ratchet-common-info.js +14 -0
- package/dist/es/histogram/histogram-entry.js +1 -0
- package/dist/es/histogram/histogram.js +50 -0
- package/dist/es/index.js +71 -0
- package/dist/es/jwt/common-jwt-token.js +1 -0
- package/dist/es/jwt/expired-jwt-handling.js +6 -0
- package/dist/es/jwt/jwt-ratchet-like.js +1 -0
- package/dist/es/jwt/jwt-ratchet.js +159 -0
- package/dist/es/jwt/jwt-token-base.js +1 -0
- package/dist/es/lang/array-ratchet.js +83 -0
- package/dist/es/lang/base64-ratchet.js +45 -0
- package/dist/es/lang/boolean-ratchet.js +45 -0
- package/dist/es/lang/composite-last-success-provider.js +24 -0
- package/dist/es/lang/date-ratchet.js +29 -0
- package/dist/es/lang/duration-ratchet.js +42 -0
- package/dist/es/lang/enum-ratchet.js +30 -0
- package/dist/es/lang/error-ratchet.js +44 -0
- package/dist/es/lang/expiring-object.js +63 -0
- package/dist/es/lang/geolocation-ratchet.js +263 -0
- package/dist/es/lang/global-ratchet.js +43 -0
- package/dist/es/lang/key-value.js +2 -0
- package/dist/es/lang/last-success-provider.js +1 -0
- package/dist/es/lang/map-ratchet.js +164 -0
- package/dist/es/lang/no.js +4 -0
- package/dist/es/lang/number-ratchet.js +152 -0
- package/dist/es/lang/parsed-url.js +1 -0
- package/dist/es/lang/promise-ratchet.js +138 -0
- package/dist/es/lang/require-ratchet.js +56 -0
- package/dist/es/lang/stop-watch.js +113 -0
- package/dist/es/lang/string-ratchet.js +191 -0
- package/dist/es/lang/time-zone-ratchet.js +76 -0
- package/dist/es/lang/timeout-token.js +15 -0
- package/dist/es/lang/transform-ratchet.js +66 -0
- package/dist/es/logger/classic-single-line-log-message-formatter.js +13 -0
- package/dist/es/logger/log-message-builder.js +47 -0
- package/dist/es/logger/log-message-format-type.js +6 -0
- package/dist/es/logger/log-message-formatter.js +1 -0
- package/dist/es/logger/log-message-processor.js +1 -0
- package/dist/es/logger/log-message.js +1 -0
- package/dist/es/logger/log-snapshot.js +1 -0
- package/dist/es/logger/logger-instance.js +201 -0
- package/dist/es/logger/logger-level-name.js +9 -0
- package/dist/es/logger/logger-meta.js +1 -0
- package/dist/es/logger/logger-options.js +1 -0
- package/dist/es/logger/logger-output-function.js +6 -0
- package/dist/es/logger/logger-ring-buffer.js +72 -0
- package/dist/es/logger/logger-util.js +44 -0
- package/dist/es/logger/logger.js +134 -0
- package/dist/es/logger/none-log-message-formatter.js +5 -0
- package/dist/es/logger/structured-json-log-message-formatter.js +19 -0
- package/dist/es/network/browser-local-ip-provider.js +21 -0
- package/dist/es/network/fixed-local-ip-provider.js +8 -0
- package/dist/es/network/local-ip-provider.js +1 -0
- package/dist/es/network/network-ratchet.js +102 -0
- package/dist/es/stream/buffer-writable.js +16 -0
- package/dist/es/stream/stream-ratchet.js +68 -0
- package/dist/es/stream/string-writable.js +14 -0
- package/dist/es/third-party/google/google-recaptcha-ratchet.js +28 -0
- package/dist/es/third-party/twilio/twilio-ratchet.js +70 -0
- package/dist/es/transform/built-in-transforms.js +191 -0
- package/dist/es/transform/transform-rule.js +1 -0
- package/dist/es/tx/transaction-configuration.js +1 -0
- package/dist/es/tx/transaction-final-state.js +6 -0
- package/dist/es/tx/transaction-ratchet.js +76 -0
- package/dist/es/tx/transaction-result.js +1 -0
- package/dist/es/tx/transaction-step.js +1 -0
- package/dist/tsconfig.cjs.tsbuildinfo +1 -0
- package/dist/tsconfig.es.tsbuildinfo +1 -0
- package/dist/tsconfig.types.tsbuildinfo +1 -0
- package/dist/types/2d/line-2d.d.ts +5 -0
- package/dist/types/2d/plane-2d.d.ts +6 -0
- package/dist/types/2d/point-2d.d.ts +4 -0
- package/dist/types/2d/poly-line-2d.d.ts +4 -0
- package/dist/types/2d/ratchet-2d.d.ts +37 -0
- package/dist/types/build/build-information.d.ts +8 -0
- package/dist/types/build/ratchet-common-info.d.ts +5 -0
- package/dist/types/histogram/histogram-entry.d.ts +4 -0
- package/dist/types/histogram/histogram.d.ts +15 -0
- package/dist/types/index.d.ts +74 -0
- package/dist/types/jwt/common-jwt-token.d.ts +17 -0
- package/dist/types/jwt/expired-jwt-handling.d.ts +5 -0
- package/dist/types/jwt/jwt-ratchet-like.d.ts +18 -0
- package/dist/types/jwt/jwt-ratchet.d.ts +39 -0
- package/dist/types/jwt/jwt-token-base.d.ts +13 -0
- package/dist/types/lang/array-ratchet.d.ts +30 -0
- package/dist/types/lang/base64-ratchet.d.ts +10 -0
- package/dist/types/lang/boolean-ratchet.d.ts +7 -0
- package/dist/types/lang/composite-last-success-provider.d.ts +8 -0
- package/dist/types/lang/date-ratchet.d.ts +11 -0
- package/dist/types/lang/duration-ratchet.d.ts +7 -0
- package/dist/types/lang/enum-ratchet.d.ts +12 -0
- package/dist/types/lang/error-ratchet.d.ts +6 -0
- package/dist/types/lang/expiring-object.d.ts +20 -0
- package/dist/types/lang/geolocation-ratchet.d.ts +40 -0
- package/dist/types/lang/global-ratchet.d.ts +6 -0
- package/dist/types/lang/key-value.d.ts +4 -0
- package/dist/types/lang/last-success-provider.d.ts +4 -0
- package/dist/types/lang/map-ratchet.d.ts +15 -0
- package/dist/types/lang/no.d.ts +3 -0
- package/dist/types/lang/number-ratchet.d.ts +20 -0
- package/dist/types/lang/parsed-url.d.ts +10 -0
- package/dist/types/lang/promise-ratchet.d.ts +32 -0
- package/dist/types/lang/require-ratchet.d.ts +11 -0
- package/dist/types/lang/stop-watch.d.ts +17 -0
- package/dist/types/lang/string-ratchet.d.ts +27 -0
- package/dist/types/lang/time-zone-ratchet.d.ts +50 -0
- package/dist/types/lang/timeout-token.d.ts +9 -0
- package/dist/types/lang/transform-ratchet.d.ts +7 -0
- package/dist/types/logger/classic-single-line-log-message-formatter.d.ts +6 -0
- package/dist/types/logger/log-message-builder.d.ts +14 -0
- package/dist/types/logger/log-message-format-type.d.ts +5 -0
- package/dist/types/logger/log-message-formatter.d.ts +5 -0
- package/dist/types/logger/log-message-processor.d.ts +5 -0
- package/dist/types/logger/log-message.d.ts +8 -0
- package/dist/types/logger/log-snapshot.d.ts +5 -0
- package/dist/types/logger/logger-instance.d.ts +46 -0
- package/dist/types/logger/logger-level-name.d.ts +8 -0
- package/dist/types/logger/logger-meta.d.ts +6 -0
- package/dist/types/logger/logger-options.d.ts +13 -0
- package/dist/types/logger/logger-output-function.d.ts +5 -0
- package/dist/types/logger/logger-ring-buffer.d.ts +18 -0
- package/dist/types/logger/logger-util.d.ts +8 -0
- package/dist/types/logger/logger.d.ts +52 -0
- package/dist/types/logger/none-log-message-formatter.d.ts +6 -0
- package/dist/types/logger/structured-json-log-message-formatter.d.ts +6 -0
- package/dist/types/network/browser-local-ip-provider.d.ts +7 -0
- package/dist/types/network/fixed-local-ip-provider.d.ts +6 -0
- package/dist/types/network/local-ip-provider.d.ts +4 -0
- package/dist/types/network/network-ratchet.d.ts +9 -0
- package/dist/types/stream/buffer-writable.d.ts +9 -0
- package/dist/types/stream/stream-ratchet.d.ts +12 -0
- package/dist/types/stream/string-writable.d.ts +8 -0
- package/dist/types/third-party/google/google-recaptcha-ratchet.d.ts +4 -0
- package/dist/types/third-party/twilio/twilio-ratchet.d.ts +15 -0
- package/dist/types/transform/built-in-transforms.d.ts +18 -0
- package/dist/types/transform/transform-rule.d.ts +3 -0
- package/dist/types/tx/transaction-configuration.d.ts +7 -0
- package/dist/types/tx/transaction-final-state.d.ts +5 -0
- package/dist/types/tx/transaction-ratchet.d.ts +6 -0
- package/dist/types/tx/transaction-result.d.ts +9 -0
- package/dist/types/tx/transaction-step.d.ts +5 -0
- package/package.json +65 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Logger } from './logger';
|
|
2
|
+
import { LoggerLevelName } from './logger-level-name';
|
|
3
|
+
export class LoggerRingBuffer {
|
|
4
|
+
constructor(size) {
|
|
5
|
+
this._lastLogMessage = { messageSource: 'No message yet', timestamp: new Date().getTime(), lvl: LoggerLevelName.info };
|
|
6
|
+
this._buffer = [];
|
|
7
|
+
this._bufferIdx = 0;
|
|
8
|
+
this._lastSnapshotIdx = 0;
|
|
9
|
+
if (!size) {
|
|
10
|
+
throw new Error('Cannot create ring buffer of size 0');
|
|
11
|
+
}
|
|
12
|
+
this._bufferSize = size;
|
|
13
|
+
}
|
|
14
|
+
get currentIndex() {
|
|
15
|
+
return this._bufferIdx;
|
|
16
|
+
}
|
|
17
|
+
get lastSnapshotIdx() {
|
|
18
|
+
return this._lastSnapshotIdx;
|
|
19
|
+
}
|
|
20
|
+
set bufferSize(newSize) {
|
|
21
|
+
if (!newSize) {
|
|
22
|
+
throw new Error('Cannot create ring buffer of size 0');
|
|
23
|
+
}
|
|
24
|
+
this._bufferSize = newSize;
|
|
25
|
+
this.clearRingBuffer();
|
|
26
|
+
}
|
|
27
|
+
getMessages(inStartFrom = null, clear = false, reverseSort = false) {
|
|
28
|
+
let rval = null;
|
|
29
|
+
if (this._bufferIdx < this._bufferSize) {
|
|
30
|
+
const start = inStartFrom == null ? 0 : inStartFrom;
|
|
31
|
+
rval = this._buffer.slice(start, this._bufferIdx);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
rval = [];
|
|
35
|
+
const firstIdx = this._bufferIdx - this._bufferSize;
|
|
36
|
+
const startFrom = inStartFrom ? Math.max(inStartFrom, firstIdx) : firstIdx;
|
|
37
|
+
for (let i = startFrom; i < this._bufferIdx; i++) {
|
|
38
|
+
rval.push(this._buffer[i % this._bufferSize]);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (clear) {
|
|
42
|
+
this.clearRingBuffer();
|
|
43
|
+
}
|
|
44
|
+
if (reverseSort) {
|
|
45
|
+
rval = rval.reverse();
|
|
46
|
+
}
|
|
47
|
+
return rval;
|
|
48
|
+
}
|
|
49
|
+
takeSnapshot() {
|
|
50
|
+
const trailingEdge = Math.max(0, this._bufferIdx - this._bufferSize);
|
|
51
|
+
const rval = {
|
|
52
|
+
messages: Logger.getMessages(this._lastSnapshotIdx),
|
|
53
|
+
logMessagesTruncated: Math.max(0, trailingEdge - this._lastSnapshotIdx),
|
|
54
|
+
};
|
|
55
|
+
this._lastSnapshotIdx = this._bufferIdx;
|
|
56
|
+
return rval;
|
|
57
|
+
}
|
|
58
|
+
getLastLogMessage() {
|
|
59
|
+
return Object.assign({}, this._lastLogMessage);
|
|
60
|
+
}
|
|
61
|
+
clearRingBuffer() {
|
|
62
|
+
this._buffer = [];
|
|
63
|
+
this._bufferIdx = 0;
|
|
64
|
+
this._lastSnapshotIdx = 0;
|
|
65
|
+
Logger.info('Cleared ring buffer (size is now %d)', this._bufferSize);
|
|
66
|
+
}
|
|
67
|
+
addToRingBuffer(newMsg) {
|
|
68
|
+
this._lastLogMessage = newMsg;
|
|
69
|
+
this._buffer[this._bufferIdx % this._bufferSize] = newMsg;
|
|
70
|
+
this._bufferIdx++;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { LoggerLevelName } from './logger-level-name';
|
|
2
|
+
import { LoggerOutputFunction } from './logger-output-function';
|
|
3
|
+
export class LoggerUtil {
|
|
4
|
+
static handlerFunctionMap(outputFn = LoggerOutputFunction.Console) {
|
|
5
|
+
const output = new Map();
|
|
6
|
+
if (outputFn === LoggerOutputFunction.StdOut) {
|
|
7
|
+
if (!process?.stdout?.write) {
|
|
8
|
+
throw new Error('Cannot use standard out - process.stdout.write not found');
|
|
9
|
+
}
|
|
10
|
+
const myStdOut = (chunk, cb) => process.stdout.write(chunk, 'utf-8', cb);
|
|
11
|
+
output.set(LoggerLevelName.error, myStdOut);
|
|
12
|
+
output.set(LoggerLevelName.warn, myStdOut);
|
|
13
|
+
output.set(LoggerLevelName.info, myStdOut);
|
|
14
|
+
output.set(LoggerLevelName.verbose, myStdOut);
|
|
15
|
+
output.set(LoggerLevelName.debug, myStdOut);
|
|
16
|
+
output.set(LoggerLevelName.silly, myStdOut);
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
output.set(LoggerLevelName.error, console.error);
|
|
20
|
+
output.set(LoggerLevelName.warn, console.warn);
|
|
21
|
+
output.set(LoggerLevelName.info, console.info);
|
|
22
|
+
output.set(LoggerLevelName.verbose, outputFn === LoggerOutputFunction.ConsoleNoDebug ? console.log : console.debug);
|
|
23
|
+
output.set(LoggerLevelName.debug, outputFn === LoggerOutputFunction.ConsoleNoDebug ? console.log : console.debug);
|
|
24
|
+
output.set(LoggerLevelName.silly, outputFn === LoggerOutputFunction.ConsoleNoDebug ? console.log : console.debug);
|
|
25
|
+
}
|
|
26
|
+
return output;
|
|
27
|
+
}
|
|
28
|
+
static defaultHandlerFunction() {
|
|
29
|
+
return console.info;
|
|
30
|
+
}
|
|
31
|
+
static levelIsEnabled(targetLevel, currentEnabled) {
|
|
32
|
+
const idxTarget = LoggerUtil.LOG_LEVELS_IN_ORDER.indexOf(targetLevel);
|
|
33
|
+
const lvl = LoggerUtil.LOG_LEVELS_IN_ORDER.indexOf(currentEnabled);
|
|
34
|
+
return idxTarget > -1 && lvl > -1 && lvl >= idxTarget;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
LoggerUtil.LOG_LEVELS_IN_ORDER = [
|
|
38
|
+
LoggerLevelName.error,
|
|
39
|
+
LoggerLevelName.warn,
|
|
40
|
+
LoggerLevelName.info,
|
|
41
|
+
LoggerLevelName.verbose,
|
|
42
|
+
LoggerLevelName.debug,
|
|
43
|
+
LoggerLevelName.silly,
|
|
44
|
+
];
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { LoggerInstance } from './logger-instance';
|
|
2
|
+
import { LogMessageFormatType } from './log-message-format-type';
|
|
3
|
+
import { LoggerLevelName } from './logger-level-name';
|
|
4
|
+
import { LoggerOutputFunction } from './logger-output-function';
|
|
5
|
+
export class Logger {
|
|
6
|
+
static applyDefaultsToOptions(input) {
|
|
7
|
+
const rval = input || {};
|
|
8
|
+
rval.initialLevel = rval.initialLevel ?? Logger.DEFAULT_OPTIONS.initialLevel;
|
|
9
|
+
rval.formatType = rval.formatType ?? Logger.DEFAULT_OPTIONS.formatType;
|
|
10
|
+
rval.trace = rval.trace ?? Logger.DEFAULT_OPTIONS.trace;
|
|
11
|
+
rval.globalVars = rval.globalVars ?? Logger.DEFAULT_OPTIONS.globalVars;
|
|
12
|
+
rval.outputFunction = rval.outputFunction ?? Logger.DEFAULT_OPTIONS.outputFunction;
|
|
13
|
+
rval.ringBufferSize = rval.ringBufferSize ?? Logger.DEFAULT_OPTIONS.ringBufferSize;
|
|
14
|
+
return rval;
|
|
15
|
+
}
|
|
16
|
+
static changeDefaultOptions(input, retroactive) {
|
|
17
|
+
if (!input || !input.initialLevel || !input.formatType) {
|
|
18
|
+
throw new Error('Default options must be non-null, and provide initial level and format type');
|
|
19
|
+
}
|
|
20
|
+
Logger.DEFAULT_OPTIONS = Object.assign({}, input);
|
|
21
|
+
if (retroactive) {
|
|
22
|
+
Array.from(Logger.LOGGER_INSTANCES.values()).forEach((li) => (li.options = input));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
static getLogger(loggerName = 'default', inOptions) {
|
|
26
|
+
let inst = Logger.LOGGER_INSTANCES.get(loggerName);
|
|
27
|
+
if (!inst) {
|
|
28
|
+
const options = Logger.applyDefaultsToOptions(inOptions);
|
|
29
|
+
inst = new LoggerInstance(loggerName, options);
|
|
30
|
+
Logger.LOGGER_INSTANCES.set(loggerName, inst);
|
|
31
|
+
}
|
|
32
|
+
return inst;
|
|
33
|
+
}
|
|
34
|
+
static recordMessageBuilder(msgBuild) {
|
|
35
|
+
return Logger.getLogger().recordMessageBuilder(msgBuild);
|
|
36
|
+
}
|
|
37
|
+
static recordMessage(msg) {
|
|
38
|
+
return Logger.getLogger().recordMessage(msg);
|
|
39
|
+
}
|
|
40
|
+
static formatMessages(msgs) {
|
|
41
|
+
return Logger.getLogger().formatMessages(msgs);
|
|
42
|
+
}
|
|
43
|
+
static updateTracePrefix(newValue) {
|
|
44
|
+
return Logger.getLogger().updateTracePrefix(newValue);
|
|
45
|
+
}
|
|
46
|
+
static changeRingBufferSize(newValue) {
|
|
47
|
+
return Logger.getLogger().changeRingBufferSize(newValue);
|
|
48
|
+
}
|
|
49
|
+
static getRingBuffer() {
|
|
50
|
+
return Logger.getLogger().ringBuffer;
|
|
51
|
+
}
|
|
52
|
+
static dumpConfigurationIntoLog() {
|
|
53
|
+
return Logger.getLogger().dumpConfigurationIntoLog();
|
|
54
|
+
}
|
|
55
|
+
static dumpOptionsIntoLog() {
|
|
56
|
+
return Logger.getLogger().dumpOptionsIntoLog();
|
|
57
|
+
}
|
|
58
|
+
static getLevel() {
|
|
59
|
+
return Logger.getLogger().level;
|
|
60
|
+
}
|
|
61
|
+
static setLevel(newLevel) {
|
|
62
|
+
Logger.getLogger().level = newLevel;
|
|
63
|
+
}
|
|
64
|
+
static getOptions() {
|
|
65
|
+
return Logger.getLogger().options;
|
|
66
|
+
}
|
|
67
|
+
static getMessages(inStartFrom = null, clear = false, reverseSort = false) {
|
|
68
|
+
const buf = Logger.getLogger().ringBuffer;
|
|
69
|
+
return buf ? buf.getMessages(inStartFrom, clear, reverseSort) : null;
|
|
70
|
+
}
|
|
71
|
+
static consoleLogPassThru(level, ...input) {
|
|
72
|
+
return Logger.getLogger().consoleLogPassThru(level, ...input);
|
|
73
|
+
}
|
|
74
|
+
static error(format, ...input) {
|
|
75
|
+
return Logger.getLogger().error(format, ...input);
|
|
76
|
+
}
|
|
77
|
+
static errorP(...input) {
|
|
78
|
+
return Logger.getLogger().errorP(...input);
|
|
79
|
+
}
|
|
80
|
+
static warn(format, ...input) {
|
|
81
|
+
return Logger.getLogger().warn(format, ...input);
|
|
82
|
+
}
|
|
83
|
+
static warnP(...input) {
|
|
84
|
+
return Logger.getLogger().warnP(...input);
|
|
85
|
+
}
|
|
86
|
+
static info(format, ...input) {
|
|
87
|
+
return Logger.getLogger().info(format, ...input);
|
|
88
|
+
}
|
|
89
|
+
static infoP(...input) {
|
|
90
|
+
return Logger.getLogger().infoP(...input);
|
|
91
|
+
}
|
|
92
|
+
static verbose(format, ...input) {
|
|
93
|
+
return Logger.getLogger().verbose(format, ...input);
|
|
94
|
+
}
|
|
95
|
+
static verboseP(...input) {
|
|
96
|
+
return Logger.getLogger().verboseP(...input);
|
|
97
|
+
}
|
|
98
|
+
static debug(format, ...input) {
|
|
99
|
+
return Logger.getLogger().debug(format, ...input);
|
|
100
|
+
}
|
|
101
|
+
static debugP(...input) {
|
|
102
|
+
return Logger.getLogger().debugP(...input);
|
|
103
|
+
}
|
|
104
|
+
static silly(format, ...input) {
|
|
105
|
+
return Logger.getLogger().silly(format, ...input);
|
|
106
|
+
}
|
|
107
|
+
static sillyP(...input) {
|
|
108
|
+
return Logger.getLogger().sillyP(...input);
|
|
109
|
+
}
|
|
110
|
+
static takeSnapshot() {
|
|
111
|
+
const buf = Logger.getLogger().ringBuffer;
|
|
112
|
+
return buf ? buf.takeSnapshot() : null;
|
|
113
|
+
}
|
|
114
|
+
static logByLevel(level, format, ...input) {
|
|
115
|
+
return Logger.getLogger().logByLevel(level, format, ...input);
|
|
116
|
+
}
|
|
117
|
+
static importMessages(msgs, prefixIn = '', addTimestamp = true) {
|
|
118
|
+
return Logger.getLogger().importMessages(msgs, prefixIn, addTimestamp);
|
|
119
|
+
}
|
|
120
|
+
static getLastLogMessage() {
|
|
121
|
+
const buf = Logger.getLogger().ringBuffer;
|
|
122
|
+
return buf ? buf.getLastLogMessage() : null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
Logger.LOGGER_INSTANCES = new Map();
|
|
126
|
+
Logger.DEFAULT_OPTIONS = {
|
|
127
|
+
initialLevel: LoggerLevelName.info,
|
|
128
|
+
formatType: LogMessageFormatType.ClassicSingleLine,
|
|
129
|
+
trace: null,
|
|
130
|
+
globalVars: {},
|
|
131
|
+
outputFunction: LoggerOutputFunction.Console,
|
|
132
|
+
ringBufferSize: 0,
|
|
133
|
+
preProcessors: [],
|
|
134
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import util from 'util';
|
|
2
|
+
export class StructuredJsonLogMessageFormatter {
|
|
3
|
+
formatMessage(msg, meta) {
|
|
4
|
+
let rval = null;
|
|
5
|
+
if (msg) {
|
|
6
|
+
const tmp = Object.assign({}, meta.options.globalVars || {}, msg.params || {});
|
|
7
|
+
tmp['msg'] = util.format(msg.messageSource, ...msg.subsVars);
|
|
8
|
+
tmp['utcDateTime'] = new Date(msg.timestamp).toISOString();
|
|
9
|
+
tmp['logLevel'] = msg.lvl;
|
|
10
|
+
if (meta.options.trace) {
|
|
11
|
+
tmp['trace'] = meta.options.trace;
|
|
12
|
+
}
|
|
13
|
+
tmp['logName'] = meta.loggerInstanceName;
|
|
14
|
+
tmp['logId'] = meta.loggerInstanceId;
|
|
15
|
+
rval = JSON.stringify(tmp) + '\n';
|
|
16
|
+
}
|
|
17
|
+
return rval;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { NetworkRatchet } from './network-ratchet';
|
|
2
|
+
import { Logger } from '../logger/logger';
|
|
3
|
+
export class BrowserLocalIpProvider {
|
|
4
|
+
constructor() {
|
|
5
|
+
this.currentIp = 'UNSET';
|
|
6
|
+
NetworkRatchet.findLocalIp(false)
|
|
7
|
+
.then((result) => {
|
|
8
|
+
Logger.info('Setting local IP to %s', result);
|
|
9
|
+
this.currentIp = result;
|
|
10
|
+
})
|
|
11
|
+
.catch((err) => {
|
|
12
|
+
Logger.warn('Unable to set current IP - leaving as UNSET : %s', err);
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
ready() {
|
|
16
|
+
return this.currentIp !== 'UNSET';
|
|
17
|
+
}
|
|
18
|
+
currentLocalIpAddress() {
|
|
19
|
+
return this.currentIp;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { Logger } from '../logger/logger';
|
|
2
|
+
export class NetworkRatchet {
|
|
3
|
+
static findLocalIp(useCache = true) {
|
|
4
|
+
Logger.info('Attempting to find local IP (V 2)');
|
|
5
|
+
if (NetworkRatchet.LOCAL_IP && useCache) {
|
|
6
|
+
return Promise.resolve(NetworkRatchet.LOCAL_IP);
|
|
7
|
+
}
|
|
8
|
+
else {
|
|
9
|
+
if (typeof window !== 'undefined') {
|
|
10
|
+
return new Promise(function (resolve, reject) {
|
|
11
|
+
try {
|
|
12
|
+
const RTCPeerConnection = window['RTCPeerConnection'] || window['webkitRTCPeerConnection'] || window['mozRTCPeerConnection'];
|
|
13
|
+
if (RTCPeerConnection) {
|
|
14
|
+
const rtc = new RTCPeerConnection({ iceServers: [] });
|
|
15
|
+
const addrs = Object.create(null);
|
|
16
|
+
addrs['0.0.0.0'] = false;
|
|
17
|
+
if (1 || window['mozRTCPeerConnection']) {
|
|
18
|
+
rtc.createDataChannel('', { reliable: false });
|
|
19
|
+
}
|
|
20
|
+
rtc.onicecandidate = function (evt) {
|
|
21
|
+
if (evt.candidate) {
|
|
22
|
+
NetworkRatchet.grepSDP('a=' + evt.candidate.candidate, addrs, resolve);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
rtc.createOffer(function (offerDesc) {
|
|
26
|
+
NetworkRatchet.grepSDP(offerDesc.sdp, addrs, resolve);
|
|
27
|
+
rtc.setLocalDescription(offerDesc);
|
|
28
|
+
}, function (e) {
|
|
29
|
+
Logger.warn('Offer failed : %s', e);
|
|
30
|
+
resolve(NetworkRatchet.updateLocalIP('FIND_UNSUPPORTED'));
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
Logger.warn('IP Address find not supported on this device');
|
|
35
|
+
resolve(NetworkRatchet.updateLocalIP('FIND_UNSUPPORTED'));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
Logger.warn('Error finding local ip address : %s', err);
|
|
40
|
+
resolve(NetworkRatchet.updateLocalIP('ERROR'));
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
Logger.warn('Window not found, cannot calculate local ip');
|
|
46
|
+
return Promise.resolve(NetworkRatchet.updateLocalIP('NO_WINDOW'));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
static parseUrl(href) {
|
|
51
|
+
const match = href.match(/^(https?\:)\/\/(([^:\/?#]*)(?:\:([0-9]+))?)([\/]{0,1}[^?#]*)(\?[^#]*|)(#.*|)$/);
|
|
52
|
+
const rval = match &&
|
|
53
|
+
{
|
|
54
|
+
href: href,
|
|
55
|
+
protocol: match[1],
|
|
56
|
+
host: match[2],
|
|
57
|
+
hostname: match[3],
|
|
58
|
+
port: match[4],
|
|
59
|
+
pathname: match[5],
|
|
60
|
+
search: match[6],
|
|
61
|
+
hash: match[7],
|
|
62
|
+
};
|
|
63
|
+
return rval;
|
|
64
|
+
}
|
|
65
|
+
static updateLocalIP(newIp) {
|
|
66
|
+
NetworkRatchet.LOCAL_IP = newIp;
|
|
67
|
+
return NetworkRatchet.LOCAL_IP;
|
|
68
|
+
}
|
|
69
|
+
static grepSDP(sdp, addrs, resolve) {
|
|
70
|
+
const hosts = [];
|
|
71
|
+
sdp.split('\r\n').forEach(function (line) {
|
|
72
|
+
if (~line.indexOf('a=candidate')) {
|
|
73
|
+
const parts = line.split(' '), addr = parts[4], type = parts[7];
|
|
74
|
+
if (type === 'host') {
|
|
75
|
+
NetworkRatchet.updateAddressList(addr, addrs, resolve);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else if (~line.indexOf('c=')) {
|
|
79
|
+
const parts = line.split(' '), addr = parts[2];
|
|
80
|
+
NetworkRatchet.updateAddressList(addr, addrs, resolve);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
static updateAddressList(newAddr, addrs, resolve) {
|
|
85
|
+
if (newAddr in addrs)
|
|
86
|
+
return;
|
|
87
|
+
else
|
|
88
|
+
addrs[newAddr] = true;
|
|
89
|
+
const displayAddrs = Object.keys(addrs).filter(function (k) {
|
|
90
|
+
return addrs[k];
|
|
91
|
+
});
|
|
92
|
+
if (displayAddrs && displayAddrs.length == 1) {
|
|
93
|
+
resolve(NetworkRatchet.updateLocalIP(displayAddrs[0]));
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
const multi = displayAddrs.sort().join(',');
|
|
97
|
+
Logger.warn('Multiple addresses found, returning sorted join : %s', multi);
|
|
98
|
+
resolve(NetworkRatchet.updateLocalIP(multi));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
NetworkRatchet.LOCAL_IP = null;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Writable } from 'stream';
|
|
2
|
+
export class BufferWritable extends Writable {
|
|
3
|
+
constructor() {
|
|
4
|
+
super();
|
|
5
|
+
this._val = [];
|
|
6
|
+
}
|
|
7
|
+
_write(chunk, encoding, callback) {
|
|
8
|
+
if (chunk) {
|
|
9
|
+
this._val.push(chunk);
|
|
10
|
+
}
|
|
11
|
+
callback();
|
|
12
|
+
}
|
|
13
|
+
get value() {
|
|
14
|
+
return Buffer.concat(this._val);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Readable } from 'stream';
|
|
2
|
+
import { ErrorRatchet } from '../lang/error-ratchet';
|
|
3
|
+
import { StringRatchet } from '../lang/string-ratchet';
|
|
4
|
+
export class StreamRatchet {
|
|
5
|
+
constructor() { }
|
|
6
|
+
static readableToBufferSync(stream) {
|
|
7
|
+
const bufs = [];
|
|
8
|
+
let next = stream.read();
|
|
9
|
+
while (next) {
|
|
10
|
+
bufs.push(next);
|
|
11
|
+
next = stream.read();
|
|
12
|
+
}
|
|
13
|
+
return Buffer.concat(bufs);
|
|
14
|
+
}
|
|
15
|
+
static async webReadableStreamToBuffer(stream) {
|
|
16
|
+
const out = [];
|
|
17
|
+
const writer = new WritableStream({
|
|
18
|
+
async write(chunk, controller) {
|
|
19
|
+
if (typeof chunk === 'string') {
|
|
20
|
+
StringRatchet.stringToUint8Array(chunk);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
out.push(chunk);
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
},
|
|
27
|
+
abort(reason) {
|
|
28
|
+
ErrorRatchet.throwFormattedErr('StringWebWritableStream failure : %s', reason);
|
|
29
|
+
},
|
|
30
|
+
}, {
|
|
31
|
+
highWaterMark: 3,
|
|
32
|
+
size: () => 1,
|
|
33
|
+
});
|
|
34
|
+
await stream.pipeTo(writer);
|
|
35
|
+
return Buffer.concat(out);
|
|
36
|
+
}
|
|
37
|
+
static async webReadableStreamToString(stream) {
|
|
38
|
+
const buf = await StreamRatchet.webReadableStreamToBuffer(stream);
|
|
39
|
+
return buf.toString();
|
|
40
|
+
}
|
|
41
|
+
static stringToReadable(input) {
|
|
42
|
+
return new Readable({
|
|
43
|
+
read() {
|
|
44
|
+
this.push(input);
|
|
45
|
+
this.push(null);
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
static stringToWebReadableStream(input) {
|
|
50
|
+
const rval = new ReadableStream({
|
|
51
|
+
start(controller) {
|
|
52
|
+
if (input) {
|
|
53
|
+
controller.enqueue(input);
|
|
54
|
+
}
|
|
55
|
+
controller.close();
|
|
56
|
+
return null;
|
|
57
|
+
},
|
|
58
|
+
}, {
|
|
59
|
+
highWaterMark: input ? input.length : null,
|
|
60
|
+
});
|
|
61
|
+
return rval;
|
|
62
|
+
}
|
|
63
|
+
static anyToStringReadable(input) {
|
|
64
|
+
return input === null || input === undefined
|
|
65
|
+
? StreamRatchet.stringToReadable(null)
|
|
66
|
+
: StreamRatchet.stringToReadable(StringRatchet.safeString(input));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Writable } from 'stream';
|
|
2
|
+
export class StringWritable extends Writable {
|
|
3
|
+
constructor() {
|
|
4
|
+
super();
|
|
5
|
+
this._val = '';
|
|
6
|
+
}
|
|
7
|
+
_write(chunk, encoding, callback) {
|
|
8
|
+
this._val += chunk ? chunk.toString() : '';
|
|
9
|
+
callback();
|
|
10
|
+
}
|
|
11
|
+
get value() {
|
|
12
|
+
return this._val;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Logger } from '../../logger/logger';
|
|
2
|
+
import { StringRatchet } from '../../lang/string-ratchet';
|
|
3
|
+
import fetch from 'cross-fetch';
|
|
4
|
+
export class GoogleRecaptchaRatchet {
|
|
5
|
+
static async verifyRecaptchaToken(keySecret, token, fetchFn = fetch) {
|
|
6
|
+
Logger.debug('Verifying recaptcha token : %s', token);
|
|
7
|
+
let rval = null;
|
|
8
|
+
if (!StringRatchet.safeString(token)) {
|
|
9
|
+
Logger.warn('Recaptcha validation error, no token passed : %s', token);
|
|
10
|
+
return rval;
|
|
11
|
+
}
|
|
12
|
+
Logger.info('Validating Recaptcha via Google API : %s', token);
|
|
13
|
+
let url = GoogleRecaptchaRatchet.GOOGLE_VERIFY_URL;
|
|
14
|
+
url = url.split('{{KEY}}').join(keySecret);
|
|
15
|
+
url = url.split('{{TOKEN}}').join(token);
|
|
16
|
+
try {
|
|
17
|
+
const resp = await fetchFn(url);
|
|
18
|
+
const body = await resp.json();
|
|
19
|
+
rval = body && body.success;
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
Logger.error('Failed to read from google : %s', err);
|
|
23
|
+
rval = false;
|
|
24
|
+
}
|
|
25
|
+
return rval;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
GoogleRecaptchaRatchet.GOOGLE_VERIFY_URL = 'https://www.google.com/recaptcha/api/siteverify?secret={{KEY}}&response={{TOKEN}}';
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import fetch from 'cross-fetch';
|
|
2
|
+
import { RequireRatchet } from '../../lang/require-ratchet';
|
|
3
|
+
import { Base64Ratchet } from '../../lang/base64-ratchet';
|
|
4
|
+
import { StringRatchet } from '../../lang/string-ratchet';
|
|
5
|
+
import { Logger } from '../../logger/logger';
|
|
6
|
+
export class TwilioRatchet {
|
|
7
|
+
constructor(accountSid, authToken, outBoundNumber) {
|
|
8
|
+
this.accountSid = accountSid;
|
|
9
|
+
this.authToken = authToken;
|
|
10
|
+
this.outBoundNumber = outBoundNumber;
|
|
11
|
+
RequireRatchet.notNullOrUndefined(accountSid, 'accountSid');
|
|
12
|
+
RequireRatchet.notNullOrUndefined(authToken, 'authToken');
|
|
13
|
+
RequireRatchet.notNullOrUndefined(outBoundNumber, 'outBoundNumber');
|
|
14
|
+
RequireRatchet.true(TwilioRatchet.isValidE164Number(outBoundNumber), 'outBoundNumber invalid format');
|
|
15
|
+
}
|
|
16
|
+
static async sendMessageDirect(accountSid, authToken, outBoundNumber, recipientPhoneNumbers, message) {
|
|
17
|
+
const ratchet = new TwilioRatchet(accountSid, authToken, outBoundNumber);
|
|
18
|
+
const rval = await ratchet.sendMessage(recipientPhoneNumbers, message);
|
|
19
|
+
return rval;
|
|
20
|
+
}
|
|
21
|
+
static generateTwilioBasicAuth(sid, authToken) {
|
|
22
|
+
const authHeader = 'Basic ' + Base64Ratchet.generateBase64VersionOfString(sid + ':' + authToken);
|
|
23
|
+
return authHeader;
|
|
24
|
+
}
|
|
25
|
+
async sendMessage(recipientPhoneNumbers, message) {
|
|
26
|
+
const rval = [];
|
|
27
|
+
RequireRatchet.notNullOrUndefined(recipientPhoneNumbers, 'recipientPhoneNumbers');
|
|
28
|
+
RequireRatchet.notNullOrUndefined(StringRatchet.trimToNull(message), 'message');
|
|
29
|
+
RequireRatchet.true(recipientPhoneNumbers.length > 0, 'recipientPhoneNumbers non-empty');
|
|
30
|
+
recipientPhoneNumbers.forEach((p) => {
|
|
31
|
+
RequireRatchet.true(TwilioRatchet.isValidE164Number(p), p + ' is not valid');
|
|
32
|
+
});
|
|
33
|
+
if (!!recipientPhoneNumbers && recipientPhoneNumbers.length > 0 && !!StringRatchet.trimToNull(message)) {
|
|
34
|
+
Logger.info('Sending %s to %j', message, recipientPhoneNumbers);
|
|
35
|
+
for (let i = 0; i < recipientPhoneNumbers.length; i++) {
|
|
36
|
+
const phoneNumber = recipientPhoneNumbers[i];
|
|
37
|
+
Logger.info('To: %s', phoneNumber);
|
|
38
|
+
if (!TwilioRatchet.isValidE164Number(phoneNumber)) {
|
|
39
|
+
throw new Error('number must be E164 format!');
|
|
40
|
+
}
|
|
41
|
+
const body = 'Body=' +
|
|
42
|
+
encodeURIComponent(message) +
|
|
43
|
+
'&From=' +
|
|
44
|
+
encodeURIComponent(this.outBoundNumber) +
|
|
45
|
+
'&To=' +
|
|
46
|
+
encodeURIComponent(phoneNumber);
|
|
47
|
+
const post = {
|
|
48
|
+
method: 'post',
|
|
49
|
+
headers: {
|
|
50
|
+
authorization: TwilioRatchet.generateTwilioBasicAuth(this.accountSid, this.authToken),
|
|
51
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
52
|
+
},
|
|
53
|
+
body: body,
|
|
54
|
+
};
|
|
55
|
+
const res = await fetch(TwilioRatchet.TWILLIO_BASE_API_URL + '/Accounts/' + this.accountSid + '/Messages.json', post);
|
|
56
|
+
const parsedResponse = await res.json();
|
|
57
|
+
Logger.debug('TwilioRatchet: For %s got %j', phoneNumber, parsedResponse);
|
|
58
|
+
rval.push(parsedResponse);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
Logger.warn('Not sending empty message / empty recipients');
|
|
63
|
+
}
|
|
64
|
+
return rval;
|
|
65
|
+
}
|
|
66
|
+
static isValidE164Number(num) {
|
|
67
|
+
return /^\+?[1-9]\d{1,14}$/.test(num);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
TwilioRatchet.TWILLIO_BASE_API_URL = 'https://api.twilio.com/2010-04-01';
|