@webority/mobile-core 0.0.25 → 0.0.26
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.txt +9 -0
- package/README.md +13 -0
- package/lib/commonjs/api/publicClient.js +4 -0
- package/lib/commonjs/api/userClient.js +10 -2
- package/lib/commonjs/index.js +7 -0
- package/lib/commonjs/logger/index.js +16 -6
- package/lib/commonjs/logger/redact.js +50 -0
- package/lib/commonjs/types/axios.js +4 -0
- package/lib/module/api/publicClient.js +4 -0
- package/lib/module/api/userClient.js +10 -2
- package/lib/module/index.js +1 -0
- package/lib/module/logger/index.js +16 -6
- package/lib/module/logger/redact.js +44 -0
- package/lib/module/types/axios.js +4 -0
- package/lib/typescript/commonjs/api/publicClient.d.ts +1 -0
- package/lib/typescript/commonjs/api/userClient.d.ts +1 -0
- package/lib/typescript/commonjs/index.d.ts +1 -0
- package/lib/typescript/commonjs/logger/redact.d.ts +4 -0
- package/lib/typescript/commonjs/types/axios.d.ts +8 -0
- package/lib/typescript/module/api/publicClient.d.ts +1 -0
- package/lib/typescript/module/api/userClient.d.ts +1 -0
- package/lib/typescript/module/index.d.ts +1 -0
- package/lib/typescript/module/logger/redact.d.ts +4 -0
- package/lib/typescript/module/types/axios.d.ts +8 -0
- package/package.json +2 -2
- package/LICENSE +0 -21
package/LICENSE.txt
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Copyright (c) Webority Technologies. All rights reserved.
|
|
2
|
+
|
|
3
|
+
This software and its NuGet packages are the proprietary and confidential property
|
|
4
|
+
of Webority Technologies. They are published publicly only for the convenience of
|
|
5
|
+
Webority's own projects and internal consumption.
|
|
6
|
+
|
|
7
|
+
No license or right to use, copy, modify, merge, publish, distribute, sublicense,
|
|
8
|
+
or create derivative works is granted to any third party. Unauthorized use,
|
|
9
|
+
reproduction, or distribution is prohibited.
|
package/README.md
CHANGED
|
@@ -47,3 +47,16 @@ keeps push on calls `enablePush` at each start.
|
|
|
47
47
|
|
|
48
48
|
Storage and network status stay on the main barrel but load no package on their own. Wire them at
|
|
49
49
|
startup with `setStorageImplementation` and `setNetworkStatusImplementation` if you want them.
|
|
50
|
+
|
|
51
|
+
## Quiet requests and log redaction
|
|
52
|
+
|
|
53
|
+
Both HTTP clients log a failed response through `Logger.error`. For a call whose failure the app
|
|
54
|
+
handles itself, pass `skipErrorLog: true` in the axios config and the clients stay silent:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
await userClient.get('/status', { skipErrorLog: true });
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`Logger` masks secrets in every message and argument before any sink sees them: `Bearer` tokens,
|
|
61
|
+
JWT-shaped strings, and the values of keys named `token`, `accessToken`, `refreshToken`,
|
|
62
|
+
`password` and `authorization` (any case) in objects and JSON strings.
|
|
@@ -7,6 +7,7 @@ exports.default = void 0;
|
|
|
7
7
|
var _axios = _interopRequireDefault(require("axios"));
|
|
8
8
|
var _index = require("../config/index.js");
|
|
9
9
|
var _index2 = require("../logger/index.js");
|
|
10
|
+
require("../types/axios.js");
|
|
10
11
|
var _baseUrl = require("./baseUrl.js");
|
|
11
12
|
var _curl = require("./curl.js");
|
|
12
13
|
var _multipart = require("./multipart.js");
|
|
@@ -58,6 +59,9 @@ publicClient.interceptors.response.use(response => {
|
|
|
58
59
|
}, error => {
|
|
59
60
|
if (_axios.default.isAxiosError(error)) {
|
|
60
61
|
const originalRequest = error.config;
|
|
62
|
+
if (originalRequest?.skipErrorLog) {
|
|
63
|
+
return Promise.reject(error);
|
|
64
|
+
}
|
|
61
65
|
if (!error.response) {
|
|
62
66
|
_index2.Logger.error(`Network error or no response from server: ${error.message}, URL: ${originalRequest?.url}`);
|
|
63
67
|
} else {
|
|
@@ -27,6 +27,7 @@ var _authStore = require("../auth/authStore.js");
|
|
|
27
27
|
var _index = require("../config/index.js");
|
|
28
28
|
var _index2 = require("../logger/index.js");
|
|
29
29
|
var _networkStatus = require("../network/networkStatus.js");
|
|
30
|
+
require("../types/axios.js");
|
|
30
31
|
var _baseUrl = require("./baseUrl.js");
|
|
31
32
|
var _curl = require("./curl.js");
|
|
32
33
|
var _multipart = require("./multipart.js");
|
|
@@ -46,6 +47,9 @@ class RequestOfflineError extends Error {
|
|
|
46
47
|
constructor(message = 'Request blocked: device is offline') {
|
|
47
48
|
super(message);
|
|
48
49
|
this.name = 'RequestOfflineError';
|
|
50
|
+
// Babel's class transform can drop the prototype link, which makes
|
|
51
|
+
// `instanceof RequestOfflineError` false in the transpiled build.
|
|
52
|
+
Object.setPrototypeOf(this, RequestOfflineError.prototype);
|
|
49
53
|
}
|
|
50
54
|
}
|
|
51
55
|
|
|
@@ -208,7 +212,9 @@ userClient.interceptors.response.use(response => response, async error => {
|
|
|
208
212
|
const axiosError = error;
|
|
209
213
|
const originalRequest = axiosError.config;
|
|
210
214
|
if (!axiosError.response) {
|
|
211
|
-
|
|
215
|
+
if (!originalRequest?.skipErrorLog) {
|
|
216
|
+
_index2.Logger.error(`Network error or no response from server: ${axiosError.message}, URL: ${originalRequest?.url}`);
|
|
217
|
+
}
|
|
212
218
|
return Promise.reject(error);
|
|
213
219
|
}
|
|
214
220
|
if (axiosError.response.status === 401 && originalRequest && !originalRequest._retry) {
|
|
@@ -250,7 +256,9 @@ userClient.interceptors.response.use(response => response, async error => {
|
|
|
250
256
|
return Promise.reject(err);
|
|
251
257
|
}
|
|
252
258
|
}
|
|
253
|
-
|
|
259
|
+
if (!originalRequest?.skipErrorLog) {
|
|
260
|
+
_index2.Logger.error(`Response error: ${axiosError.response?.data ?? axiosError.message}, URL: ${originalRequest?.url}, Status: ${axiosError.response.status}`);
|
|
261
|
+
}
|
|
254
262
|
return Promise.reject(error);
|
|
255
263
|
});
|
|
256
264
|
var _default = exports.default = userClient;
|
package/lib/commonjs/index.js
CHANGED
|
@@ -501,6 +501,12 @@ Object.defineProperty(exports, "publicClient", {
|
|
|
501
501
|
return _publicClient.default;
|
|
502
502
|
}
|
|
503
503
|
});
|
|
504
|
+
Object.defineProperty(exports, "refreshAccessToken", {
|
|
505
|
+
enumerable: true,
|
|
506
|
+
get: function () {
|
|
507
|
+
return _tokenRefresh.refreshAccessToken;
|
|
508
|
+
}
|
|
509
|
+
});
|
|
504
510
|
Object.defineProperty(exports, "removeToken", {
|
|
505
511
|
enumerable: true,
|
|
506
512
|
get: function () {
|
|
@@ -612,6 +618,7 @@ Object.defineProperty(exports, "validatePhoneNumberLength", {
|
|
|
612
618
|
var _curl = require("./api/curl.js");
|
|
613
619
|
var _publicClient = _interopRequireDefault(require("./api/publicClient.js"));
|
|
614
620
|
var _retry = require("./api/retry.js");
|
|
621
|
+
var _tokenRefresh = require("./api/tokenRefresh.js");
|
|
615
622
|
var _userClient = _interopRequireWildcard(require("./api/userClient.js"));
|
|
616
623
|
var _authStore = require("./auth/authStore.js");
|
|
617
624
|
var _jwt = require("./auth/jwt.js");
|
|
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.setRemoteLogger = exports.setDeviceContext = exports.getDeviceContext = exports.configureLogger = exports.Logger = void 0;
|
|
7
7
|
var _index = require("../config/index.js");
|
|
8
|
+
var _redact = require("./redact.js");
|
|
8
9
|
// ANSI color codes
|
|
9
10
|
const Colors = {
|
|
10
11
|
RESET: '\x1b[0m',
|
|
@@ -209,21 +210,27 @@ const forwardErrorToRemote = (err, context) => {
|
|
|
209
210
|
}
|
|
210
211
|
safe(() => remote?.recordError?.(err, buildErrorContext(context, suppressedCount)));
|
|
211
212
|
};
|
|
212
|
-
const logInfo = (
|
|
213
|
+
const logInfo = (rawMessage, ...rawParams) => {
|
|
214
|
+
const message = (0, _redact.redactString)(rawMessage);
|
|
215
|
+
const optionalParams = (0, _redact.redact)(rawParams);
|
|
213
216
|
if (!isEnabled() || !isLogLevelAllowed(LogLevels.INFO.level)) {
|
|
214
217
|
return;
|
|
215
218
|
}
|
|
216
219
|
console.info(`${LogLevels.INFO.color}[INFO]: ${message}${Colors.RESET}`, ...optionalParams);
|
|
217
220
|
safe(() => remote?.log?.('info', message, optionalParams));
|
|
218
221
|
};
|
|
219
|
-
const logWarning = (
|
|
222
|
+
const logWarning = (rawMessage, ...rawParams) => {
|
|
223
|
+
const message = (0, _redact.redactString)(rawMessage);
|
|
224
|
+
const optionalParams = (0, _redact.redact)(rawParams);
|
|
220
225
|
if (!isEnabled() || !isLogLevelAllowed(LogLevels.WARN.level)) {
|
|
221
226
|
return;
|
|
222
227
|
}
|
|
223
228
|
console.warn(`${LogLevels.WARN.color}[WARNING]: ${message}${Colors.RESET}`, ...optionalParams);
|
|
224
229
|
safe(() => remote?.log?.('warn', message, optionalParams));
|
|
225
230
|
};
|
|
226
|
-
const logError = (
|
|
231
|
+
const logError = (rawMessage, ...rawParams) => {
|
|
232
|
+
const message = (0, _redact.redactString)(rawMessage);
|
|
233
|
+
const optionalParams = (0, _redact.redact)(rawParams);
|
|
227
234
|
if (isEnabled() && isLogLevelAllowed(LogLevels.ERROR.level)) {
|
|
228
235
|
console.error(`${LogLevels.ERROR.color}[ERROR]: ${message}${Colors.RESET}`, ...optionalParams);
|
|
229
236
|
}
|
|
@@ -239,14 +246,17 @@ const logError = (message, ...optionalParams) => {
|
|
|
239
246
|
});
|
|
240
247
|
}
|
|
241
248
|
};
|
|
242
|
-
const breadcrumb = (
|
|
249
|
+
const breadcrumb = (rawMessage, rawData) => {
|
|
250
|
+
const message = (0, _redact.redactString)(rawMessage);
|
|
251
|
+
const data = (0, _redact.redact)(rawData);
|
|
243
252
|
if (isEnabled() && isLogLevelAllowed('info')) {
|
|
244
253
|
console.info(`${Colors.BLUE}[BREADCRUMB]: ${message}${Colors.RESET}`, data ?? '');
|
|
245
254
|
}
|
|
246
255
|
safe(() => remote?.breadcrumb?.(message, data));
|
|
247
256
|
};
|
|
248
|
-
const recordError = (error,
|
|
249
|
-
const err = toErrorObject(error);
|
|
257
|
+
const recordError = (error, rawContext) => {
|
|
258
|
+
const err = (0, _redact.redact)(toErrorObject(error));
|
|
259
|
+
const context = (0, _redact.redact)(rawContext);
|
|
250
260
|
if (isEnabled() && isLogLevelAllowed('error')) {
|
|
251
261
|
console.error(`${Colors.RED_BOLD}[RECORDED]: ${err.message}${Colors.RESET}`, context ?? '');
|
|
252
262
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.redactString = exports.redact = void 0;
|
|
7
|
+
const REDACTED = '[REDACTED]';
|
|
8
|
+
const SECRET_KEYS = /^(token|accesstoken|refreshtoken|password|authorization)$/i;
|
|
9
|
+
const BEARER = /\bBearer\s+[A-Za-z0-9._~+/-]+=*/gi;
|
|
10
|
+
const JWT = /\beyJ[A-Za-z0-9_-]*\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]*/g;
|
|
11
|
+
const KEYED_VALUE = /(["']?(?:token|accessToken|refreshToken|password|authorization)["']?\s*[:=]\s*)(?:"(?:[^"\\]|\\.)*"|'[^']*'|[^\s,;&}]+)/gi;
|
|
12
|
+
const MAX_DEPTH = 6;
|
|
13
|
+
const redactString = input => input.replace(BEARER, `Bearer ${REDACTED}`).replace(JWT, REDACTED).replace(KEYED_VALUE, (_match, prefix) => `${prefix}"${REDACTED}"`);
|
|
14
|
+
exports.redactString = redactString;
|
|
15
|
+
const redactInner = (value, depth, seen) => {
|
|
16
|
+
if (typeof value === 'string') {
|
|
17
|
+
return redactString(value);
|
|
18
|
+
}
|
|
19
|
+
if (value === null || typeof value !== 'object') {
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
if (value instanceof Error) {
|
|
23
|
+
value.message = redactString(value.message);
|
|
24
|
+
if (value.stack) {
|
|
25
|
+
value.stack = redactString(value.stack);
|
|
26
|
+
}
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
if (depth >= MAX_DEPTH || seen.has(value)) {
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
seen.add(value);
|
|
33
|
+
if (Array.isArray(value)) {
|
|
34
|
+
return value.map(item => redactInner(item, depth + 1, seen));
|
|
35
|
+
}
|
|
36
|
+
const proto = Object.getPrototypeOf(value);
|
|
37
|
+
if (proto !== Object.prototype && proto !== null) {
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
const out = {};
|
|
41
|
+
for (const [key, item] of Object.entries(value)) {
|
|
42
|
+
out[key] = SECRET_KEYS.test(key) ? REDACTED : redactInner(item, depth + 1, seen);
|
|
43
|
+
}
|
|
44
|
+
return out;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/** Returns a copy with secrets masked; Errors are masked in place so identity and stack survive. */
|
|
48
|
+
const redact = value => redactInner(value, 0, new WeakSet());
|
|
49
|
+
exports.redact = redact;
|
|
50
|
+
//# sourceMappingURL=redact.js.map
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import axios from 'axios';
|
|
4
4
|
import { getConfigValue } from "../config/index.js";
|
|
5
5
|
import { Logger } from "../logger/index.js";
|
|
6
|
+
import "../types/axios.js";
|
|
6
7
|
import { applyConfiguredBaseUrl } from "./baseUrl.js";
|
|
7
8
|
import { logCurl } from "./curl.js";
|
|
8
9
|
import { sendFormDataAsMultipart } from "./multipart.js";
|
|
@@ -54,6 +55,9 @@ publicClient.interceptors.response.use(response => {
|
|
|
54
55
|
}, error => {
|
|
55
56
|
if (axios.isAxiosError(error)) {
|
|
56
57
|
const originalRequest = error.config;
|
|
58
|
+
if (originalRequest?.skipErrorLog) {
|
|
59
|
+
return Promise.reject(error);
|
|
60
|
+
}
|
|
57
61
|
if (!error.response) {
|
|
58
62
|
Logger.error(`Network error or no response from server: ${error.message}, URL: ${originalRequest?.url}`);
|
|
59
63
|
} else {
|
|
@@ -5,6 +5,7 @@ import { ACCESS_TOKEN_KEY, getToken } from "../auth/authStore.js";
|
|
|
5
5
|
import { getConfigValue } from "../config/index.js";
|
|
6
6
|
import { Logger } from "../logger/index.js";
|
|
7
7
|
import { getNetworkStatus } from "../network/networkStatus.js";
|
|
8
|
+
import "../types/axios.js";
|
|
8
9
|
import { applyConfiguredBaseUrl } from "./baseUrl.js";
|
|
9
10
|
import { logCurl } from "./curl.js";
|
|
10
11
|
import { sendFormDataAsMultipart } from "./multipart.js";
|
|
@@ -25,6 +26,9 @@ export class RequestOfflineError extends Error {
|
|
|
25
26
|
constructor(message = 'Request blocked: device is offline') {
|
|
26
27
|
super(message);
|
|
27
28
|
this.name = 'RequestOfflineError';
|
|
29
|
+
// Babel's class transform can drop the prototype link, which makes
|
|
30
|
+
// `instanceof RequestOfflineError` false in the transpiled build.
|
|
31
|
+
Object.setPrototypeOf(this, RequestOfflineError.prototype);
|
|
28
32
|
}
|
|
29
33
|
}
|
|
30
34
|
|
|
@@ -186,7 +190,9 @@ userClient.interceptors.response.use(response => response, async error => {
|
|
|
186
190
|
const axiosError = error;
|
|
187
191
|
const originalRequest = axiosError.config;
|
|
188
192
|
if (!axiosError.response) {
|
|
189
|
-
|
|
193
|
+
if (!originalRequest?.skipErrorLog) {
|
|
194
|
+
Logger.error(`Network error or no response from server: ${axiosError.message}, URL: ${originalRequest?.url}`);
|
|
195
|
+
}
|
|
190
196
|
return Promise.reject(error);
|
|
191
197
|
}
|
|
192
198
|
if (axiosError.response.status === 401 && originalRequest && !originalRequest._retry) {
|
|
@@ -228,7 +234,9 @@ userClient.interceptors.response.use(response => response, async error => {
|
|
|
228
234
|
return Promise.reject(err);
|
|
229
235
|
}
|
|
230
236
|
}
|
|
231
|
-
|
|
237
|
+
if (!originalRequest?.skipErrorLog) {
|
|
238
|
+
Logger.error(`Response error: ${axiosError.response?.data ?? axiosError.message}, URL: ${originalRequest?.url}, Status: ${axiosError.response.status}`);
|
|
239
|
+
}
|
|
232
240
|
return Promise.reject(error);
|
|
233
241
|
});
|
|
234
242
|
export default userClient;
|
package/lib/module/index.js
CHANGED
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
export { buildCurl, logCurl } from "./api/curl.js";
|
|
28
28
|
export { default as publicClient } from "./api/publicClient.js";
|
|
29
29
|
export { attachRetry, isRetryableStatus } from "./api/retry.js";
|
|
30
|
+
export { refreshAccessToken } from "./api/tokenRefresh.js";
|
|
30
31
|
export { default as userClient, injectStore, injectUserAuth, RequestOfflineError, resetRefreshState, SESSION_TERMINATION_CODES } from "./api/userClient.js";
|
|
31
32
|
// Auth / token storage
|
|
32
33
|
export { ACCESS_TOKEN_KEY, getToken, REFRESH_TOKEN_KEY, removeToken, setKeychainImplementation, storeToken } from "./auth/authStore.js";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import { getConfigValue } from "../config/index.js";
|
|
4
|
+
import { redact, redactString } from "./redact.js";
|
|
4
5
|
|
|
5
6
|
// ANSI color codes
|
|
6
7
|
const Colors = {
|
|
@@ -203,21 +204,27 @@ const forwardErrorToRemote = (err, context) => {
|
|
|
203
204
|
}
|
|
204
205
|
safe(() => remote?.recordError?.(err, buildErrorContext(context, suppressedCount)));
|
|
205
206
|
};
|
|
206
|
-
const logInfo = (
|
|
207
|
+
const logInfo = (rawMessage, ...rawParams) => {
|
|
208
|
+
const message = redactString(rawMessage);
|
|
209
|
+
const optionalParams = redact(rawParams);
|
|
207
210
|
if (!isEnabled() || !isLogLevelAllowed(LogLevels.INFO.level)) {
|
|
208
211
|
return;
|
|
209
212
|
}
|
|
210
213
|
console.info(`${LogLevels.INFO.color}[INFO]: ${message}${Colors.RESET}`, ...optionalParams);
|
|
211
214
|
safe(() => remote?.log?.('info', message, optionalParams));
|
|
212
215
|
};
|
|
213
|
-
const logWarning = (
|
|
216
|
+
const logWarning = (rawMessage, ...rawParams) => {
|
|
217
|
+
const message = redactString(rawMessage);
|
|
218
|
+
const optionalParams = redact(rawParams);
|
|
214
219
|
if (!isEnabled() || !isLogLevelAllowed(LogLevels.WARN.level)) {
|
|
215
220
|
return;
|
|
216
221
|
}
|
|
217
222
|
console.warn(`${LogLevels.WARN.color}[WARNING]: ${message}${Colors.RESET}`, ...optionalParams);
|
|
218
223
|
safe(() => remote?.log?.('warn', message, optionalParams));
|
|
219
224
|
};
|
|
220
|
-
const logError = (
|
|
225
|
+
const logError = (rawMessage, ...rawParams) => {
|
|
226
|
+
const message = redactString(rawMessage);
|
|
227
|
+
const optionalParams = redact(rawParams);
|
|
221
228
|
if (isEnabled() && isLogLevelAllowed(LogLevels.ERROR.level)) {
|
|
222
229
|
console.error(`${LogLevels.ERROR.color}[ERROR]: ${message}${Colors.RESET}`, ...optionalParams);
|
|
223
230
|
}
|
|
@@ -233,14 +240,17 @@ const logError = (message, ...optionalParams) => {
|
|
|
233
240
|
});
|
|
234
241
|
}
|
|
235
242
|
};
|
|
236
|
-
const breadcrumb = (
|
|
243
|
+
const breadcrumb = (rawMessage, rawData) => {
|
|
244
|
+
const message = redactString(rawMessage);
|
|
245
|
+
const data = redact(rawData);
|
|
237
246
|
if (isEnabled() && isLogLevelAllowed('info')) {
|
|
238
247
|
console.info(`${Colors.BLUE}[BREADCRUMB]: ${message}${Colors.RESET}`, data ?? '');
|
|
239
248
|
}
|
|
240
249
|
safe(() => remote?.breadcrumb?.(message, data));
|
|
241
250
|
};
|
|
242
|
-
const recordError = (error,
|
|
243
|
-
const err = toErrorObject(error);
|
|
251
|
+
const recordError = (error, rawContext) => {
|
|
252
|
+
const err = redact(toErrorObject(error));
|
|
253
|
+
const context = redact(rawContext);
|
|
244
254
|
if (isEnabled() && isLogLevelAllowed('error')) {
|
|
245
255
|
console.error(`${Colors.RED_BOLD}[RECORDED]: ${err.message}${Colors.RESET}`, context ?? '');
|
|
246
256
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const REDACTED = '[REDACTED]';
|
|
4
|
+
const SECRET_KEYS = /^(token|accesstoken|refreshtoken|password|authorization)$/i;
|
|
5
|
+
const BEARER = /\bBearer\s+[A-Za-z0-9._~+/-]+=*/gi;
|
|
6
|
+
const JWT = /\beyJ[A-Za-z0-9_-]*\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]*/g;
|
|
7
|
+
const KEYED_VALUE = /(["']?(?:token|accessToken|refreshToken|password|authorization)["']?\s*[:=]\s*)(?:"(?:[^"\\]|\\.)*"|'[^']*'|[^\s,;&}]+)/gi;
|
|
8
|
+
const MAX_DEPTH = 6;
|
|
9
|
+
export const redactString = input => input.replace(BEARER, `Bearer ${REDACTED}`).replace(JWT, REDACTED).replace(KEYED_VALUE, (_match, prefix) => `${prefix}"${REDACTED}"`);
|
|
10
|
+
const redactInner = (value, depth, seen) => {
|
|
11
|
+
if (typeof value === 'string') {
|
|
12
|
+
return redactString(value);
|
|
13
|
+
}
|
|
14
|
+
if (value === null || typeof value !== 'object') {
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
if (value instanceof Error) {
|
|
18
|
+
value.message = redactString(value.message);
|
|
19
|
+
if (value.stack) {
|
|
20
|
+
value.stack = redactString(value.stack);
|
|
21
|
+
}
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
if (depth >= MAX_DEPTH || seen.has(value)) {
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
seen.add(value);
|
|
28
|
+
if (Array.isArray(value)) {
|
|
29
|
+
return value.map(item => redactInner(item, depth + 1, seen));
|
|
30
|
+
}
|
|
31
|
+
const proto = Object.getPrototypeOf(value);
|
|
32
|
+
if (proto !== Object.prototype && proto !== null) {
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
const out = {};
|
|
36
|
+
for (const [key, item] of Object.entries(value)) {
|
|
37
|
+
out[key] = SECRET_KEYS.test(key) ? REDACTED : redactInner(item, depth + 1, seen);
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/** Returns a copy with secrets masked; Errors are masked in place so identity and stack survive. */
|
|
43
|
+
export const redact = value => redactInner(value, 0, new WeakSet());
|
|
44
|
+
//# sourceMappingURL=redact.js.map
|
|
@@ -25,6 +25,7 @@ export { buildCurl, logCurl } from './api/curl';
|
|
|
25
25
|
export { default as publicClient } from './api/publicClient';
|
|
26
26
|
export type { RetryPolicy } from './api/retry';
|
|
27
27
|
export { attachRetry, isRetryableStatus } from './api/retry';
|
|
28
|
+
export { refreshAccessToken } from './api/tokenRefresh';
|
|
28
29
|
export type { RefreshableStore, SessionTerminationCode } from './api/userClient';
|
|
29
30
|
export { default as userClient, injectStore, injectUserAuth, RequestOfflineError, resetRefreshState, SESSION_TERMINATION_CODES } from './api/userClient';
|
|
30
31
|
export type { KeychainLike, SecureCredentials, StoredToken } from './auth/authStore';
|
|
@@ -25,6 +25,7 @@ export { buildCurl, logCurl } from './api/curl.js';
|
|
|
25
25
|
export { default as publicClient } from './api/publicClient.js';
|
|
26
26
|
export type { RetryPolicy } from './api/retry.js';
|
|
27
27
|
export { attachRetry, isRetryableStatus } from './api/retry.js';
|
|
28
|
+
export { refreshAccessToken } from './api/tokenRefresh.js';
|
|
28
29
|
export type { RefreshableStore, SessionTerminationCode } from './api/userClient.js';
|
|
29
30
|
export { default as userClient, injectStore, injectUserAuth, RequestOfflineError, resetRefreshState, SESSION_TERMINATION_CODES } from './api/userClient.js';
|
|
30
31
|
export type { KeychainLike, SecureCredentials, StoredToken } from './auth/authStore.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webority/mobile-core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.26",
|
|
4
4
|
"description": "Platform layer for Webority React Native apps: HTTP clients, auth/token storage, config, logging, formatters, validators, network status, permissions, storage and version checks. No UI.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-native",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"webority"
|
|
15
15
|
],
|
|
16
16
|
"homepage": "https://www.webority.com",
|
|
17
|
-
"license": "
|
|
17
|
+
"license": "SEE LICENSE IN LICENSE.txt",
|
|
18
18
|
"author": {
|
|
19
19
|
"name": "Webority Technologies",
|
|
20
20
|
"email": "contact@webority.com",
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 Webority Technologies
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|