@aidc-toolkit/core 1.0.31-beta → 1.0.33-beta
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/README.md +98 -87
- package/dist/app-data-storage.d.ts +118 -0
- package/dist/app-data-storage.d.ts.map +1 -0
- package/dist/app-data-storage.js +117 -0
- package/dist/app-data-storage.js.map +1 -0
- package/dist/app-data.d.ts +26 -0
- package/dist/app-data.d.ts.map +1 -0
- package/dist/app-data.js +79 -0
- package/dist/app-data.js.map +1 -0
- package/dist/browser-app-data-storage.d.ts +26 -0
- package/dist/browser-app-data-storage.d.ts.map +1 -0
- package/dist/browser-app-data-storage.js +34 -0
- package/dist/browser-app-data-storage.js.map +1 -0
- package/dist/cache.d.ts +58 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +12 -0
- package/dist/cache.js.map +1 -0
- package/dist/file-app-data-storage.d.ts +26 -0
- package/dist/file-app-data-storage.d.ts.map +1 -0
- package/dist/file-app-data-storage.js +40 -0
- package/dist/file-app-data-storage.js.map +1 -0
- package/dist/hyperlink.d.ts +18 -0
- package/dist/hyperlink.d.ts.map +1 -0
- package/dist/hyperlink.js +2 -0
- package/dist/hyperlink.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/local-app-data-storage.d.ts +8 -0
- package/dist/local-app-data-storage.d.ts.map +1 -0
- package/dist/local-app-data-storage.js +11 -0
- package/dist/local-app-data-storage.js.map +1 -0
- package/dist/locale/en/locale-resources.d.ts +10 -0
- package/dist/locale/en/locale-resources.d.ts.map +1 -0
- package/dist/locale/en/locale-resources.js +9 -0
- package/dist/locale/en/locale-resources.js.map +1 -0
- package/dist/locale/fr/locale-resources.d.ts +10 -0
- package/dist/locale/fr/locale-resources.d.ts.map +1 -0
- package/dist/locale/fr/locale-resources.js +9 -0
- package/dist/locale/fr/locale-resources.js.map +1 -0
- package/dist/locale/i18n.d.ts +33 -6
- package/dist/locale/i18n.d.ts.map +1 -1
- package/dist/locale/i18n.js +76 -31
- package/dist/locale/i18n.js.map +1 -1
- package/dist/logger.d.ts +108 -4
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +227 -12
- package/dist/logger.js.map +1 -1
- package/dist/remote-app-data-storage.d.ts +18 -0
- package/dist/remote-app-data-storage.d.ts.map +1 -0
- package/dist/remote-app-data-storage.js +37 -0
- package/dist/remote-app-data-storage.js.map +1 -0
- package/dist/type-helper.js.map +1 -1
- package/dist/type.d.ts +5 -0
- package/dist/type.d.ts.map +1 -1
- package/package.json +10 -8
- package/src/app-data-storage.ts +166 -0
- package/src/app-data.ts +94 -0
- package/src/browser-app-data-storage.ts +37 -0
- package/src/cache.ts +64 -0
- package/src/file-app-data-storage.ts +49 -0
- package/src/hyperlink.ts +19 -0
- package/src/index.ts +10 -0
- package/src/local-app-data-storage.ts +12 -0
- package/src/locale/en/locale-resources.ts +8 -0
- package/src/locale/fr/locale-resources.ts +8 -0
- package/src/locale/i18n.ts +102 -36
- package/src/locale/i18next.d.ts +16 -0
- package/src/logger.ts +250 -13
- package/src/remote-app-data-storage.ts +38 -0
- package/src/type-helper.ts +2 -2
- package/src/type.ts +6 -0
package/src/logger.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Logger } from "tslog";
|
|
1
|
+
import { type ISettingsParam, Logger } from "tslog";
|
|
2
|
+
import { i18nextCore } from "./locale/i18n.js";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Log levels.
|
|
@@ -24,29 +25,265 @@ export type LogLevelKey = keyof typeof LogLevels;
|
|
|
24
25
|
export type LogLevel = typeof LogLevels[LogLevelKey];
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
|
-
* Get
|
|
28
|
+
* Get the log level enumeration value corresponding to a string or number.
|
|
28
29
|
*
|
|
29
|
-
* @param
|
|
30
|
-
*
|
|
30
|
+
* @param untypedLogLevel
|
|
31
|
+
* Untyped log level.
|
|
31
32
|
*
|
|
32
33
|
* @returns
|
|
33
|
-
*
|
|
34
|
+
* Typed log level or default `LogLevels.Info` if untyped log level not provided..
|
|
34
35
|
*/
|
|
35
|
-
export function
|
|
36
|
-
let
|
|
36
|
+
export function logLevelOf(untypedLogLevel?: string | number): LogLevel {
|
|
37
|
+
let typedLogLevel: LogLevel;
|
|
37
38
|
|
|
38
|
-
if (typeof
|
|
39
|
-
if (
|
|
39
|
+
if (typeof untypedLogLevel === "string") {
|
|
40
|
+
if (untypedLogLevel in LogLevels) {
|
|
40
41
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- String exists as a key.
|
|
41
|
-
|
|
42
|
+
typedLogLevel = LogLevels[untypedLogLevel as LogLevelKey];
|
|
43
|
+
} else {
|
|
44
|
+
throw new RangeError(i18nextCore.t("Logger.unknownLogLevel", {
|
|
45
|
+
logLevel: untypedLogLevel
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
} else if (untypedLogLevel !== undefined) {
|
|
49
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Assume that valid log level has been provided.
|
|
50
|
+
if (Object.values(LogLevels).includes(untypedLogLevel as LogLevel)) {
|
|
51
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Valid log level has been provided.
|
|
52
|
+
typedLogLevel = untypedLogLevel as LogLevel;
|
|
42
53
|
} else {
|
|
43
|
-
throw new
|
|
54
|
+
throw new RangeError(i18nextCore.t("Logger.unknownLogLevel", {
|
|
55
|
+
logLevel: untypedLogLevel
|
|
56
|
+
}));
|
|
44
57
|
}
|
|
45
58
|
} else {
|
|
46
|
-
|
|
59
|
+
typedLogLevel = LogLevels.Info;
|
|
47
60
|
}
|
|
48
61
|
|
|
62
|
+
return typedLogLevel;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get a logger with an optional log level. The underlying implementation is
|
|
67
|
+
* [`tslog`](https://tslog.js.org/).
|
|
68
|
+
*
|
|
69
|
+
* @param logLevel
|
|
70
|
+
* Log level as enumeration value or string. Mapped to `minLevel` and sets `hideLogPositionForProduction` to true in
|
|
71
|
+
* settings if at {@linkcode LogLevels.Info} or higher. Default is {@linkcode LogLevels.Info}.
|
|
72
|
+
*
|
|
73
|
+
* @param settings
|
|
74
|
+
* Detailed settings. See [`tslog`](https://tslog.js.org/#/?id=settings) documentation for details. The `minLevel` is
|
|
75
|
+
* ignored in favour of `logLevel` but `hideLogPositionForProduction` will override the default logic.
|
|
76
|
+
*
|
|
77
|
+
* @param logObj
|
|
78
|
+
* Default log object. See [`tslog`](https://tslog.js.org/#/?id=defining-and-accessing-logobj) documentation for
|
|
79
|
+
* details.
|
|
80
|
+
*
|
|
81
|
+
* @returns
|
|
82
|
+
* Logger.
|
|
83
|
+
*
|
|
84
|
+
* @template T
|
|
85
|
+
* Log object type.
|
|
86
|
+
*/
|
|
87
|
+
export function getLogger<T extends object = object>(logLevel?: string | number, settings?: ISettingsParam<T>, logObj?: T): Logger<T> {
|
|
88
|
+
const minLevel = logLevelOf(logLevel);
|
|
89
|
+
|
|
49
90
|
return new Logger({
|
|
91
|
+
// Hiding log position for production can be overridden in settings parameter.
|
|
92
|
+
hideLogPositionForProduction: minLevel >= LogLevels.Info,
|
|
93
|
+
...settings ?? {},
|
|
94
|
+
// Minimum log level overrides settings parameter.
|
|
50
95
|
minLevel
|
|
51
|
-
});
|
|
96
|
+
}, logObj);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Get a loggable representation of a value. Values are returned unmodified, except as follows:
|
|
101
|
+
*
|
|
102
|
+
* - Big integers are converted to whole numbers where possible, otherwise as their decimal string representations.
|
|
103
|
+
* - Arrays are limited to a maximum of ten elements. Any array longer than ten elements is replaced with the first four
|
|
104
|
+
* elements, a string of three dots, and the last four elements. This may still create large results for
|
|
105
|
+
* multidimensional arrays.
|
|
106
|
+
* - Errors are converted to objects with `name`, `message`, and `stack` properties.
|
|
107
|
+
* - Symbols are converted to their string representations.
|
|
108
|
+
* - Functions are converted to strings of the form `Function(name)`.
|
|
109
|
+
*
|
|
110
|
+
* @param value
|
|
111
|
+
* Value.
|
|
112
|
+
*
|
|
113
|
+
* @returns
|
|
114
|
+
* Loggable value.
|
|
115
|
+
*/
|
|
116
|
+
export function loggableValue(value: unknown): unknown {
|
|
117
|
+
let replacementValue: unknown;
|
|
118
|
+
|
|
119
|
+
switch (typeof value) {
|
|
120
|
+
case "string":
|
|
121
|
+
case "number":
|
|
122
|
+
case "boolean":
|
|
123
|
+
case "undefined":
|
|
124
|
+
replacementValue = value;
|
|
125
|
+
break;
|
|
126
|
+
|
|
127
|
+
case "bigint":
|
|
128
|
+
// Big integers not supported in JSON.
|
|
129
|
+
replacementValue = value >= Number.MIN_SAFE_INTEGER && value <= Number.MAX_SAFE_INTEGER ? Number(value) : value.toString(10);
|
|
130
|
+
break;
|
|
131
|
+
|
|
132
|
+
case "object":
|
|
133
|
+
if (value === null) {
|
|
134
|
+
replacementValue = value;
|
|
135
|
+
} else if (Array.isArray(value)) {
|
|
136
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- Slicing array is necessary to keep log size down.
|
|
137
|
+
replacementValue = (value.length <= 10 ? value : [...value.slice(0, 4), "...", ...value.slice(-4)]).map(entry => loggableValue(entry));
|
|
138
|
+
} else if (value instanceof Error) {
|
|
139
|
+
replacementValue = loggableValue({
|
|
140
|
+
name: value.name,
|
|
141
|
+
message: value.message,
|
|
142
|
+
stack: value.stack?.split("\n")
|
|
143
|
+
});
|
|
144
|
+
} else {
|
|
145
|
+
// Apply recursively to all properties of the object.
|
|
146
|
+
replacementValue = Object.fromEntries(Object.entries(value).map(([k, v]) => [k, loggableValue(v)]));
|
|
147
|
+
}
|
|
148
|
+
break;
|
|
149
|
+
|
|
150
|
+
case "symbol":
|
|
151
|
+
replacementValue = value.toString();
|
|
152
|
+
break;
|
|
153
|
+
|
|
154
|
+
case "function":
|
|
155
|
+
replacementValue = `Function(${value.name})`;
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return replacementValue;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Logger transport that stores messages in memory.
|
|
164
|
+
*/
|
|
165
|
+
export class MemoryTransport<T extends object> {
|
|
166
|
+
/**
|
|
167
|
+
* Notification callbacks map.
|
|
168
|
+
*/
|
|
169
|
+
readonly #notificationCallbacksMap = new Map<string, (message: string | undefined, messages: readonly string[]) => void>();
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Messages.
|
|
173
|
+
*/
|
|
174
|
+
readonly #messages: string[] = [];
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Maximum length of messages array.
|
|
178
|
+
*/
|
|
179
|
+
#maximumLength = 0;
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Length to which messages array is truncated when maximum is reached.
|
|
183
|
+
*/
|
|
184
|
+
#truncateLength = 0;
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Constructor.
|
|
188
|
+
*
|
|
189
|
+
* @param logger
|
|
190
|
+
* Logger.
|
|
191
|
+
*
|
|
192
|
+
* @param maximumLength
|
|
193
|
+
* Maximum length of messages array.
|
|
194
|
+
*
|
|
195
|
+
* @param truncateLength
|
|
196
|
+
* Length to which messages array is truncated when maximum is reached. Default is 50% of `maximumLength`, maximum
|
|
197
|
+
* is 80% of `maximumLength`.
|
|
198
|
+
*/
|
|
199
|
+
constructor(logger: Logger<T>, maximumLength: number, truncateLength?: number) {
|
|
200
|
+
this.resize(maximumLength, truncateLength);
|
|
201
|
+
|
|
202
|
+
logger.attachTransport((logObject) => {
|
|
203
|
+
// Truncate logger messages if necessary.
|
|
204
|
+
if (this.#messages.length >= this.#maximumLength) {
|
|
205
|
+
this.#messages.splice(0, this.#maximumLength - this.#truncateLength);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const message = JSON.stringify(logObject);
|
|
209
|
+
|
|
210
|
+
this.#messages.push(message);
|
|
211
|
+
|
|
212
|
+
// Notify all registered callbacks.
|
|
213
|
+
for (const notificationCallback of this.#notificationCallbacksMap.values()) {
|
|
214
|
+
notificationCallback(message, this.#messages);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Get the messages.
|
|
221
|
+
*/
|
|
222
|
+
get messages(): string[] {
|
|
223
|
+
return this.#messages;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Get the maximum length of messages array.
|
|
228
|
+
*/
|
|
229
|
+
get maximumLength(): number {
|
|
230
|
+
return this.#maximumLength;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Get the length to which messages array is truncated when maximum is reached.
|
|
235
|
+
*/
|
|
236
|
+
get truncateLength(): number {
|
|
237
|
+
return this.#truncateLength;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Add a notification callback. If one already exists under the current name, do nothing.
|
|
242
|
+
*
|
|
243
|
+
* @param name
|
|
244
|
+
* Callback name.
|
|
245
|
+
*
|
|
246
|
+
* @param notificationCallback
|
|
247
|
+
* Callback.
|
|
248
|
+
*
|
|
249
|
+
* @returns
|
|
250
|
+
* True if successfully added.
|
|
251
|
+
*/
|
|
252
|
+
addNotificationCallback(name: string, notificationCallback: (message: string | undefined, messages: readonly string[]) => void): boolean {
|
|
253
|
+
const added = !this.#notificationCallbacksMap.has(name);
|
|
254
|
+
|
|
255
|
+
if (added) {
|
|
256
|
+
this.#notificationCallbacksMap.set(name, notificationCallback);
|
|
257
|
+
|
|
258
|
+
// Notify with existing messages.
|
|
259
|
+
notificationCallback(undefined, this.#messages);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return added;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Remove a notification callback.
|
|
267
|
+
*
|
|
268
|
+
* @param name
|
|
269
|
+
* Callback name.
|
|
270
|
+
*/
|
|
271
|
+
removeNotificationCallback(name: string): void {
|
|
272
|
+
this.#notificationCallbacksMap.delete(name);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Resize the messages array.
|
|
277
|
+
*
|
|
278
|
+
* @param maximumLength
|
|
279
|
+
* Maximum length of messages array.
|
|
280
|
+
*
|
|
281
|
+
* @param truncateLength
|
|
282
|
+
* Length to which messages array is truncated when maximum is reached. Default is 50% of `maximumLength`, maximum
|
|
283
|
+
* is 80% of `maximumLength`.
|
|
284
|
+
*/
|
|
285
|
+
resize(maximumLength: number, truncateLength?: number): void {
|
|
286
|
+
this.#maximumLength = maximumLength;
|
|
287
|
+
this.#truncateLength = truncateLength !== undefined ? Math.min(truncateLength, Math.floor(maximumLength * 0.8)) : Math.floor(maximumLength / 2);
|
|
288
|
+
}
|
|
52
289
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ReadOnlyAppDataStorage } from "./app-data-storage.js";
|
|
2
|
+
import { i18nextCore } from "./locale/i18n.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Remote application data storage using HTTP. The `store()` and `delete()` methods are not supported.
|
|
6
|
+
*/
|
|
7
|
+
export class RemoteAppDataStorage extends ReadOnlyAppDataStorage<true> {
|
|
8
|
+
/**
|
|
9
|
+
* Constructor.
|
|
10
|
+
*
|
|
11
|
+
* @param baseURL
|
|
12
|
+
* Base URL. The URL must not end with a slash.
|
|
13
|
+
*/
|
|
14
|
+
constructor(baseURL: string) {
|
|
15
|
+
super(true, baseURL);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @inheritDoc
|
|
20
|
+
*/
|
|
21
|
+
protected override async doRead(key: string, asBinary: boolean | undefined): Promise<string | Uint8Array | undefined> {
|
|
22
|
+
return fetch(key).then(async (response) => {
|
|
23
|
+
let result: string | Uint8Array | undefined;
|
|
24
|
+
|
|
25
|
+
if (response.ok) {
|
|
26
|
+
result = asBinary === true ? new Uint8Array(await response.arrayBuffer()) : await response.text();
|
|
27
|
+
} else if (response.status === 404) {
|
|
28
|
+
result = undefined;
|
|
29
|
+
} else {
|
|
30
|
+
throw new RangeError(i18nextCore.t("RemoteAppDataStorage.httpError", {
|
|
31
|
+
status: response.status
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return result;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
package/src/type-helper.ts
CHANGED
|
@@ -94,7 +94,7 @@ export function pick<T extends object, K extends keyof T>(o: T, ...keys: K[]): P
|
|
|
94
94
|
*/
|
|
95
95
|
export function exclude<TWide extends TNarrow, TNarrow extends object, K extends keyof TNarrow>(wide: TWide, narrow: TNarrow): Omit<TWide, K> {
|
|
96
96
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Keys are valid.
|
|
97
|
-
return omit(wide, ...
|
|
97
|
+
return omit(wide, ...Object.keys(narrow) as K[]);
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
/**
|
|
@@ -120,7 +120,7 @@ export function exclude<TWide extends TNarrow, TNarrow extends object, K extends
|
|
|
120
120
|
*/
|
|
121
121
|
export function include<TWide extends TNarrow, TNarrow extends object, K extends keyof TNarrow>(wide: TWide, narrow: TNarrow): Pick<TWide, K> {
|
|
122
122
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Keys are valid.
|
|
123
|
-
return pick(wide, ...
|
|
123
|
+
return pick(wide, ...Object.keys(narrow) as K[]);
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
/**
|
package/src/type.ts
CHANGED
|
@@ -63,6 +63,12 @@ export type TypedConstructor<TConstructor extends abstract new (...args: Constru
|
|
|
63
63
|
export type TypedAbstractConstructor<TConstructor extends abstract new (...args: ConstructorParameters<TConstructor>) => InstanceType<TConstructor>> =
|
|
64
64
|
AbstractConstructor<ConstructorParameters<TConstructor>, InstanceType<TConstructor>>;
|
|
65
65
|
|
|
66
|
+
/**
|
|
67
|
+
* Promisable type. Extends a type by allowing a {@linkcode Promise} of the same type. Typically used in abstract method
|
|
68
|
+
* declarations where the implementing class may or may not implement the method as asynchronous.
|
|
69
|
+
*/
|
|
70
|
+
export type Promisable<T> = T | Promise<T>;
|
|
71
|
+
|
|
66
72
|
/**
|
|
67
73
|
* Determine the fundamental promised type. This is stricter than `Awaited<Type>` in that it requires a {@linkcode
|
|
68
74
|
* Promise}.
|