@nu-art/ts-common 0.401.9 → 0.500.0

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.
@@ -1,4 +1,4 @@
1
- import { ModuleManager } from "./module-manager.js";
1
+ import { ModuleManager } from './module-manager.js';
2
2
  /**
3
3
  * Application class that extends ModuleManager with startup callback support.
4
4
  *
@@ -15,7 +15,7 @@
15
15
  * See the License for the specific language governing permissions and
16
16
  * limitations under the License.
17
17
  */
18
- import { ModuleManager } from "./module-manager.js";
18
+ import { ModuleManager } from './module-manager.js';
19
19
  /**
20
20
  * Application class that extends ModuleManager with startup callback support.
21
21
  *
@@ -52,9 +52,9 @@ export class Application extends ModuleManager {
52
52
  super.build();
53
53
  onStarted && onStarted()
54
54
  .then((data) => {
55
- data && this.logInfo("data: ", data);
56
- this.logInfo("Completed");
55
+ data && this.logInfo('data: ', data);
56
+ this.logInfo('Completed');
57
57
  })
58
- .catch((err) => this.logError("Error", err));
58
+ .catch((err) => this.logError('Error', err));
59
59
  }
60
60
  }
@@ -1 +1,2 @@
1
1
  export * from '@nu-art/logger';
2
+ export { LogClient_Browser, LogClient_BrowserGroups } from '@nu-art/logger/browser';
@@ -1 +1,2 @@
1
1
  export * from '@nu-art/logger';
2
+ export { LogClient_Browser, LogClient_BrowserGroups } from '@nu-art/logger/browser';
package/core/module.d.ts CHANGED
@@ -4,7 +4,6 @@
4
4
  import { ModuleManager } from './module-manager.js';
5
5
  import { Logger, LogLevel } from './logger/index.js';
6
6
  import { ValidatorTypeResolver } from '../validator/validator-core.js';
7
- import { TimerHandler } from '../utils/date-time-tools.js';
8
7
  /**
9
8
  * Base abstract class for all modules in the nu-art ecosystem.
10
9
  *
@@ -45,6 +44,7 @@ export declare abstract class Module<Config = any, ModuleConfig extends Config &
45
44
  } = Config & {
46
45
  minLogLevel?: LogLevel;
47
46
  }, ConfigValidator extends ValidatorTypeResolver<ModuleConfig> = ValidatorTypeResolver<ModuleConfig>> extends Logger {
47
+ private readonly classStack;
48
48
  private name;
49
49
  /** Module configuration, merged from default config and ModuleManager-provided config */
50
50
  readonly config: ModuleConfig;
@@ -54,10 +54,6 @@ export declare abstract class Module<Config = any, ModuleConfig extends Config &
54
54
  protected readonly initiated = false;
55
55
  /** Optional config validator, set via setConfigValidator() */
56
56
  protected readonly configValidator?: ConfigValidator;
57
- /** Internal map for managing debounce/throttle timeouts by key */
58
- protected timeoutMap: {
59
- [k: string]: number;
60
- };
61
57
  /**
62
58
  * Creates a new Module instance.
63
59
  *
@@ -68,43 +64,9 @@ export declare abstract class Module<Config = any, ModuleConfig extends Config &
68
64
  * @throws {BadImplementationException} If the class name doesn't end with `_Class`
69
65
  */
70
66
  constructor(tag?: string);
71
- /**
72
- * Debounces a function call, canceling any pending execution with the same key
73
- * and scheduling a new execution after the specified delay.
74
- *
75
- * Each call with the same key cancels the previous pending execution and resets
76
- * the timer. Useful for rate-limiting user input or API calls.
77
- *
78
- * @param handler - Function to execute after the delay
79
- * @param key - Unique key to identify this debounced operation. Multiple calls
80
- * with the same key will cancel previous pending executions.
81
- * @param ms - Delay in milliseconds before executing the handler (default: 0)
82
- *
83
- * @example
84
- * ```typescript
85
- * // Debounce search input
86
- * this.debounce(() => this.performSearch(query), 'search', 300);
87
- * ```
88
- */
89
- debounce(handler: TimerHandler, key: string, ms?: number): void;
90
- /**
91
- * Throttles a function call, ensuring it executes at most once per time period.
92
- *
93
- * Unlike debounce, throttle executes immediately if no execution is pending,
94
- * then prevents further executions until the time period expires. Useful for
95
- * limiting the frequency of expensive operations.
96
- *
97
- * @param handler - Function to execute
98
- * @param key - Unique key to identify this throttled operation
99
- * @param ms - Minimum time in milliseconds between executions (default: 0)
100
- *
101
- * @example
102
- * ```typescript
103
- * // Throttle scroll handler
104
- * this.throttle(() => this.updateScrollPosition(), 'scroll', 100);
105
- * ```
106
- */
107
- throttle(handler: TimerHandler, key: string, ms?: number): void;
67
+ protected addToClassStack: (cls: Function) => void;
68
+ isInstanceOf: <T extends Function>(cls: T) => this is T;
69
+ isInstanceType: <T extends Function>(cls: T) => this is T;
108
70
  /**
109
71
  * Sets a config validator for runtime validation of module configuration.
110
72
  *
package/core/module.js CHANGED
@@ -18,7 +18,7 @@
18
18
  import { BadImplementationException } from './exceptions/exceptions.js';
19
19
  import { merge } from '../utils/merge-tools.js';
20
20
  import { Logger } from './logger/index.js';
21
- import { _clearTimeout, _setTimeout } from '../utils/date-time-tools.js';
21
+ import { lastElement } from '../utils/array-tools.js';
22
22
  /**
23
23
  * Base abstract class for all modules in the nu-art ecosystem.
24
24
  *
@@ -55,6 +55,7 @@ import { _clearTimeout, _setTimeout } from '../utils/date-time-tools.js';
55
55
  * ```
56
56
  */
57
57
  export class Module extends Logger {
58
+ classStack = [];
58
59
  name;
59
60
  /** Module configuration, merged from default config and ModuleManager-provided config */
60
61
  config = {};
@@ -64,8 +65,6 @@ export class Module extends Logger {
64
65
  initiated = false;
65
66
  /** Optional config validator, set via setConfigValidator() */
66
67
  configValidator;
67
- /** Internal map for managing debounce/throttle timeouts by key */
68
- timeoutMap = {};
69
68
  /**
70
69
  * Creates a new Module instance.
71
70
  *
@@ -83,68 +82,15 @@ export class Module extends Logger {
83
82
  throw new BadImplementationException(`Found module named: ${this.name}, Module class MUST end with '_Class' e.g. MyModule_Class`);
84
83
  this.name = this.name.replace('_Class', '');
85
84
  }
86
- /**
87
- * Debounces a function call, canceling any pending execution with the same key
88
- * and scheduling a new execution after the specified delay.
89
- *
90
- * Each call with the same key cancels the previous pending execution and resets
91
- * the timer. Useful for rate-limiting user input or API calls.
92
- *
93
- * @param handler - Function to execute after the delay
94
- * @param key - Unique key to identify this debounced operation. Multiple calls
95
- * with the same key will cancel previous pending executions.
96
- * @param ms - Delay in milliseconds before executing the handler (default: 0)
97
- *
98
- * @example
99
- * ```typescript
100
- * // Debounce search input
101
- * this.debounce(() => this.performSearch(query), 'search', 300);
102
- * ```
103
- */
104
- debounce(handler, key, ms = 0) {
105
- _clearTimeout(this.timeoutMap[key]);
106
- this.timeoutMap[key] = _setTimeout(handler, ms);
107
- }
108
- // // possibly to add
109
- // public async debounceSync(handler: TimerHandler, key: string, ms = 0) {
110
- // _clearTimeout(this.timeoutMap[key]);
111
- //
112
- // await new Promise((resolve, reject) => {
113
- // this.timeoutMap[key] = setTimeout(async (..._args) => {
114
- // try {
115
- // await handler(..._args);
116
- // resolve();
117
- // } catch (e:any) {
118
- // reject(e);
119
- // }
120
- // }, ms) as unknown as number;
121
- // });
122
- // }
123
- /**
124
- * Throttles a function call, ensuring it executes at most once per time period.
125
- *
126
- * Unlike debounce, throttle executes immediately if no execution is pending,
127
- * then prevents further executions until the time period expires. Useful for
128
- * limiting the frequency of expensive operations.
129
- *
130
- * @param handler - Function to execute
131
- * @param key - Unique key to identify this throttled operation
132
- * @param ms - Minimum time in milliseconds between executions (default: 0)
133
- *
134
- * @example
135
- * ```typescript
136
- * // Throttle scroll handler
137
- * this.throttle(() => this.updateScrollPosition(), 'scroll', 100);
138
- * ```
139
- */
140
- throttle(handler, key, ms = 0) {
141
- if (this.timeoutMap[key])
142
- return;
143
- this.timeoutMap[key] = _setTimeout(() => {
144
- handler();
145
- delete this.timeoutMap[key];
146
- }, ms);
147
- }
85
+ addToClassStack = (cls) => {
86
+ this.classStack.push(cls.name);
87
+ };
88
+ isInstanceOf = (cls) => {
89
+ return this.classStack.includes(cls.name);
90
+ };
91
+ isInstanceType = (cls) => {
92
+ return lastElement(this.classStack) === cls.name;
93
+ };
148
94
  /**
149
95
  * Sets a config validator for runtime validation of module configuration.
150
96
  *
package/index.d.ts CHANGED
@@ -35,4 +35,5 @@ export * from './validator/validator-core.js';
35
35
  export * from './validator/validators.js';
36
36
  export * from './validator/type-validators.js';
37
37
  export * from './consts/consts.js';
38
+ export * from './mem-cache/index.js';
38
39
  export * from './modules/csv-serializer.js';
package/index.js CHANGED
@@ -52,4 +52,5 @@ export * from './validator/validator-core.js';
52
52
  export * from './validator/validators.js';
53
53
  export * from './validator/type-validators.js';
54
54
  export * from './consts/consts.js';
55
+ export * from './mem-cache/index.js';
55
56
  export * from './modules/csv-serializer.js';
@@ -0,0 +1,57 @@
1
+ import { TypedMap } from '../utils/types.js';
2
+ /** Key reference for lookup: string id or partial object to resolve via keyToId */
3
+ export type MemCacheKeyRef = string | Record<string, unknown>;
4
+ /**
5
+ * Options for constructing a MemCache. Id extraction is pluggable; no DB or domain types.
6
+ */
7
+ export type MemCacheOptions<T extends object> = {
8
+ /** Extracts a stable string id from an item. Used for map storage and delta updates. */
9
+ getId: (item: T) => string;
10
+ /** Resolves a lookup key (string or partial object) to id. Omit if lookups are always by string id. */
11
+ keyToId?: (key: MemCacheKeyRef) => string;
12
+ };
13
+ /**
14
+ * In-memory cache with pluggable id extraction.
15
+ *
16
+ * Provides fast, synchronous access with filtering, mapping, unique lookups, and delta updates.
17
+ * Items are stored frozen. No dependency on DB or Proto; app provides getId/keyToId.
18
+ *
19
+ * @template T - Item type
20
+ */
21
+ export declare class MemCache<T extends object> {
22
+ private readonly getId;
23
+ private readonly keyToId;
24
+ loaded: boolean;
25
+ private _map;
26
+ private _array;
27
+ protected cacheFilter?: (item: Readonly<T>) => boolean;
28
+ constructor(options: MemCacheOptions<T>);
29
+ setCacheFilter: (filter: (item: Readonly<T>) => boolean) => void;
30
+ getCacheFilter: () => ((item: Readonly<T>) => boolean) | undefined;
31
+ forEach: (processor: (item: Readonly<T>) => void) => void;
32
+ clear: () => void;
33
+ /**
34
+ * Load items into cache. Items are frozen.
35
+ */
36
+ load(items: T[]): void;
37
+ private resolveKey;
38
+ uniqueAssert: (key?: MemCacheKeyRef) => Readonly<T>;
39
+ unique: (key?: MemCacheKeyRef) => Readonly<T> | undefined;
40
+ all: () => Readonly<Readonly<T>[]>;
41
+ allMutable: () => Readonly<T>[];
42
+ filter: (filter: (item: Readonly<T>, index: number, array: Readonly<T[]>) => boolean) => Readonly<T>[];
43
+ byIds: (ids: MemCacheKeyRef[]) => (Readonly<T> | undefined)[];
44
+ find: (filter: (item: Readonly<T>, index: number, array: Readonly<T[]>) => boolean) => Readonly<T> | undefined;
45
+ map: <U>(mapper: (item: Readonly<T>, index: number, array: Readonly<T[]>) => U) => U[];
46
+ sort: (map?: keyof T | (keyof T)[] | ((item: Readonly<T>) => unknown), invert?: boolean) => Readonly<T>[];
47
+ arrayToMap: (getKey: (item: Readonly<T>, index: number, map: TypedMap<Readonly<T>>) => string | number | (string | number)[], map?: TypedMap<Readonly<T>>) => TypedMap<Readonly<T>>;
48
+ /**
49
+ * Update cache after entries are deleted. Uses getId for identity.
50
+ */
51
+ onEntriesDeleted(itemsDeleted: T[]): void;
52
+ /**
53
+ * Update cache after entries are updated/created. Uses getId for identity.
54
+ */
55
+ onEntriesUpdated(itemsUpdated: T[]): void;
56
+ protected setCache(cacheArray: Readonly<T>[]): void;
57
+ }
@@ -0,0 +1,95 @@
1
+ /*
2
+ * ts-common - Core TypeScript infrastructure
3
+ * Copyright (C) 2020 Adam van der Kruk aka TacB0sS
4
+ * Licensed under the Apache License, Version 2.0
5
+ */
6
+ import { arrayToMap, sortArray } from '../utils/array-tools.js';
7
+ import { BadImplementationException } from '../core/exceptions/exceptions.js';
8
+ /**
9
+ * In-memory cache with pluggable id extraction.
10
+ *
11
+ * Provides fast, synchronous access with filtering, mapping, unique lookups, and delta updates.
12
+ * Items are stored frozen. No dependency on DB or Proto; app provides getId/keyToId.
13
+ *
14
+ * @template T - Item type
15
+ */
16
+ export class MemCache {
17
+ getId;
18
+ keyToId;
19
+ loaded = false;
20
+ _map;
21
+ _array;
22
+ cacheFilter;
23
+ constructor(options) {
24
+ this.getId = options.getId;
25
+ this.keyToId = options.keyToId;
26
+ this.clear();
27
+ }
28
+ setCacheFilter = (filter) => {
29
+ this.cacheFilter = filter;
30
+ };
31
+ getCacheFilter = () => this.cacheFilter;
32
+ forEach = (processor) => {
33
+ this._array.forEach(processor);
34
+ };
35
+ clear = () => {
36
+ this.setCache([]);
37
+ this.loaded = false;
38
+ };
39
+ /**
40
+ * Load items into cache. Items are frozen.
41
+ */
42
+ load(items) {
43
+ const frozen = items.map(item => Object.freeze(item));
44
+ this.setCache(frozen);
45
+ this.loaded = true;
46
+ }
47
+ resolveKey(key) {
48
+ if (typeof key === 'string')
49
+ return key;
50
+ if (this.keyToId)
51
+ return this.keyToId(key);
52
+ return undefined;
53
+ }
54
+ uniqueAssert = (key) => {
55
+ const item = this.unique(key);
56
+ if (!item)
57
+ throw new BadImplementationException(`Missing expected item for keys: ${JSON.stringify(key)}`);
58
+ return item;
59
+ };
60
+ unique = (key) => {
61
+ if (key === undefined)
62
+ return undefined;
63
+ const id = this.resolveKey(key);
64
+ return id !== undefined ? this._map[id] : undefined;
65
+ };
66
+ all = () => this._array;
67
+ allMutable = () => [...this._array];
68
+ filter = (filter) => this.all().filter(filter);
69
+ byIds = (ids) => ids.map(id => this.unique(id));
70
+ find = (filter) => this.all().find(filter);
71
+ map = (mapper) => this.all().map(mapper);
72
+ sort = (map = (i) => i, invert = false) => sortArray(this.allMutable(), map, invert);
73
+ arrayToMap = (getKey, map = {}) => arrayToMap(this.allMutable(), getKey, map);
74
+ /**
75
+ * Update cache after entries are deleted. Uses getId for identity.
76
+ */
77
+ onEntriesDeleted(itemsDeleted) {
78
+ const ids = new Set(itemsDeleted.map(this.getId));
79
+ this.setCache(this.filter(i => !ids.has(this.getId(i))));
80
+ }
81
+ /**
82
+ * Update cache after entries are updated/created. Uses getId for identity.
83
+ */
84
+ onEntriesUpdated(itemsUpdated) {
85
+ const frozen = itemsUpdated.map(item => Object.freeze(item));
86
+ const ids = new Set(itemsUpdated.map(this.getId));
87
+ const toCache = this.filter(i => !ids.has(this.getId(i)));
88
+ toCache.push(...frozen);
89
+ this.setCache(toCache);
90
+ }
91
+ setCache(cacheArray) {
92
+ this._map = Object.freeze({ ...arrayToMap(cacheArray, (item) => this.getId(item)) });
93
+ this._array = Object.freeze(cacheArray);
94
+ }
95
+ }
@@ -0,0 +1 @@
1
+ export * from './MemCache.js';
@@ -0,0 +1,6 @@
1
+ /*
2
+ * ts-common - Core TypeScript infrastructure
3
+ * Copyright (C) 2020 Adam van der Kruk aka TacB0sS
4
+ * Licensed under the Apache License, Version 2.0
5
+ */
6
+ export * from './MemCache.js';
@@ -86,6 +86,12 @@ export declare class MemStorage {
86
86
  * Provides a type-safe interface for accessing MemStorage values.
87
87
  * Supports unique keys (prevent overwriting), lazy resolution, and assertions.
88
88
  *
89
+ * **Design – never set nothing**: MemKeys must never be set to undefined or null.
90
+ * There is no point in setting something that is nothing; it would be like deleting
91
+ * or overwriting relevant state that should persist. Callers must use a meaningful
92
+ * empty value for their type (e.g. `''` for string, `{}` for object) when the logical
93
+ * value is "absent". `set()` throws if given undefined or null.
94
+ *
89
95
  * **Usage**:
90
96
  * ```typescript
91
97
  * const userKey = new MemKey<User>('user', true); // unique key
@@ -128,6 +128,12 @@ export class MemStorage {
128
128
  * Provides a type-safe interface for accessing MemStorage values.
129
129
  * Supports unique keys (prevent overwriting), lazy resolution, and assertions.
130
130
  *
131
+ * **Design – never set nothing**: MemKeys must never be set to undefined or null.
132
+ * There is no point in setting something that is nothing; it would be like deleting
133
+ * or overwriting relevant state that should persist. Callers must use a meaningful
134
+ * empty value for their type (e.g. `''` for string, `{}` for object) when the logical
135
+ * value is "absent". `set()` throws if given undefined or null.
136
+ *
131
137
  * **Usage**:
132
138
  * ```typescript
133
139
  * const userKey = new MemKey<User>('user', true); // unique key
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nu-art/ts-common",
3
- "version": "0.401.9",
3
+ "version": "0.500.0",
4
4
  "description": "Core TypeScript infrastructure library for building modular applications with lifecycle management, logging, validation, and utilities",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -37,8 +37,8 @@
37
37
  "run-tests": "ts-mocha --timeout 50000 -p src/test/tsconfig.json src/test/run-all-tests.ts"
38
38
  },
39
39
  "dependencies": {
40
- "@nu-art/testalot": "0.401.9",
41
- "@nu-art/logger": "0.401.9",
40
+ "@nu-art/testalot": "0.500.0",
41
+ "@nu-art/logger": "0.500.0",
42
42
  "fast-csv": "^5.0.2",
43
43
  "export-to-csv": "0.2.1",
44
44
  "moment": "^2.29.4",
@@ -9,7 +9,11 @@ export const DB_OBJECT_PROP__CREATED = '__created';
9
9
  /** Database object property name for update timestamp */
10
10
  export const DB_OBJECT_PROP__UPDATED = '__updated';
11
11
  /** Array of all database object metadata keys */
12
- export const KeysOfDB_Object = [DB_OBJECT_PROP__ID, DB_OBJECT_PROP__VERSION, DB_OBJECT_PROP__CREATED, DB_OBJECT_PROP__UPDATED, '__metadata1'];
12
+ export const KeysOfDB_Object = [DB_OBJECT_PROP__ID,
13
+ DB_OBJECT_PROP__VERSION,
14
+ DB_OBJECT_PROP__CREATED,
15
+ DB_OBJECT_PROP__UPDATED,
16
+ '__metadata1'];
13
17
  /**
14
18
  * Extracts the ID from a database object.
15
19
  *
@@ -15,7 +15,7 @@
15
15
  * See the License for the specific language governing permissions and
16
16
  * limitations under the License.
17
17
  */
18
- import md from "node-forge";
18
+ import md from 'node-forge';
19
19
  /**
20
20
  * Computes MD5 hash of input data.
21
21
  *
@@ -84,7 +84,7 @@ export function sha512(toBeConverted) {
84
84
  * @param encoding - Target encoding (default: "base64")
85
85
  * @returns Encoded string
86
86
  */
87
- export function encode(data, encoding = "base64") {
87
+ export function encode(data, encoding = 'base64') {
88
88
  let buffer;
89
89
  if (Buffer.isBuffer(data))
90
90
  buffer = data;
@@ -102,6 +102,6 @@ export function encode(data, encoding = "base64") {
102
102
  * @param to - Target encoding (default: "utf8")
103
103
  * @returns Decoded string
104
104
  */
105
- export function decode(encoded, from = "base64", to = "utf8") {
105
+ export function decode(encoded, from = 'base64', to = 'utf8') {
106
106
  return Buffer.from(encoded, from).toString(to);
107
107
  }
package/utils/index.d.ts CHANGED
@@ -1,27 +1,27 @@
1
- export * from "./array-tools.js";
2
- export * from "./conflict-tools.js";
3
- export * from "./crypto-tools.js";
4
- export * from "./date-time-tools.js";
5
- export * from "./db-object-tools.js";
6
- export * from "./exception-tools.js";
7
- export * from "./filter-tools.js";
8
- export * from "./hash-tools.js";
9
- export * from "./index.js";
10
- export * from "./json-tools.js";
11
- export * from "./merge-tools.js";
12
- export * from "./mimetype-tools.js";
13
- export * from "./number-tools.js";
14
- export * from "./object-tools.js";
15
- export * from "./promise-tools.js";
16
- export * from "./query-params.js";
17
- export * from "./queue.js";
18
- export * from "./queue-v2.js";
19
- export * from "./random-tools.js";
20
- export * from "./storage-capacity-tools.js";
21
- export * from "./string-tools.js";
22
- export * from "./time-proxy.js";
23
- export * from "./tools.js";
24
- export * from "./types.js";
25
- export * from "./ui-tools.js";
26
- export * from "./url-tools.js";
27
- export * from "./version-tools.js";
1
+ export * from './array-tools.js';
2
+ export * from './conflict-tools.js';
3
+ export * from './crypto-tools.js';
4
+ export * from './date-time-tools.js';
5
+ export * from './db-object-tools.js';
6
+ export * from './exception-tools.js';
7
+ export * from './filter-tools.js';
8
+ export * from './hash-tools.js';
9
+ export * from './index.js';
10
+ export * from './json-tools.js';
11
+ export * from './merge-tools.js';
12
+ export * from './mimetype-tools.js';
13
+ export * from './number-tools.js';
14
+ export * from './object-tools.js';
15
+ export * from './promise-tools.js';
16
+ export * from './query-params.js';
17
+ export * from './queue.js';
18
+ export * from './queue-v2.js';
19
+ export * from './random-tools.js';
20
+ export * from './storage-capacity-tools.js';
21
+ export * from './string-tools.js';
22
+ export * from './time-proxy.js';
23
+ export * from './tools.js';
24
+ export * from './types.js';
25
+ export * from './ui-tools.js';
26
+ export * from './url-tools.js';
27
+ export * from './version-tools.js';
package/utils/index.js CHANGED
@@ -1,27 +1,27 @@
1
- export * from "./array-tools.js";
2
- export * from "./conflict-tools.js";
3
- export * from "./crypto-tools.js";
4
- export * from "./date-time-tools.js";
5
- export * from "./db-object-tools.js";
6
- export * from "./exception-tools.js";
7
- export * from "./filter-tools.js";
8
- export * from "./hash-tools.js";
9
- export * from "./index.js";
10
- export * from "./json-tools.js";
11
- export * from "./merge-tools.js";
12
- export * from "./mimetype-tools.js";
13
- export * from "./number-tools.js";
14
- export * from "./object-tools.js";
15
- export * from "./promise-tools.js";
16
- export * from "./query-params.js";
17
- export * from "./queue.js";
18
- export * from "./queue-v2.js";
19
- export * from "./random-tools.js";
20
- export * from "./storage-capacity-tools.js";
21
- export * from "./string-tools.js";
22
- export * from "./time-proxy.js";
23
- export * from "./tools.js";
24
- export * from "./types.js";
25
- export * from "./ui-tools.js";
26
- export * from "./url-tools.js";
27
- export * from "./version-tools.js";
1
+ export * from './array-tools.js';
2
+ export * from './conflict-tools.js';
3
+ export * from './crypto-tools.js';
4
+ export * from './date-time-tools.js';
5
+ export * from './db-object-tools.js';
6
+ export * from './exception-tools.js';
7
+ export * from './filter-tools.js';
8
+ export * from './hash-tools.js';
9
+ export * from './index.js';
10
+ export * from './json-tools.js';
11
+ export * from './merge-tools.js';
12
+ export * from './mimetype-tools.js';
13
+ export * from './number-tools.js';
14
+ export * from './object-tools.js';
15
+ export * from './promise-tools.js';
16
+ export * from './query-params.js';
17
+ export * from './queue.js';
18
+ export * from './queue-v2.js';
19
+ export * from './random-tools.js';
20
+ export * from './storage-capacity-tools.js';
21
+ export * from './string-tools.js';
22
+ export * from './time-proxy.js';
23
+ export * from './tools.js';
24
+ export * from './types.js';
25
+ export * from './ui-tools.js';
26
+ export * from './url-tools.js';
27
+ export * from './version-tools.js';
@@ -28,4 +28,3 @@ export declare function generateUUID(): string;
28
28
  * @returns 8-character string for short URL
29
29
  */
30
30
  export declare function generateShortURL(): string;
31
- export declare const generateLoremIpsum: (length: number) => string;
@@ -64,27 +64,3 @@ export function generateShortURL() {
64
64
  }
65
65
  return result;
66
66
  }
67
- const loremIpsum = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at mi sapien. Proin viverra massa turpis, quis vehicula nibh maximus eu. Integer mi ante, fermentum id rutrum et, condimentum sed quam. Mauris tristique scelerisque nibh eget dignissim. Nulla blandit leo sit amet sem dignissim cursus. Nulla malesuada imperdiet purus, eget dignissim ex elementum eget. Suspendisse consequat lorem eget mauris suscipit congue. Suspendisse potenti. Suspendisse rutrum ligula non ipsum posuere sollicitudin. Morbi iaculis, mauris mollis aliquet convallis, tortor nulla luctus elit, nec pretium eros risus eu sapien. Phasellus congue nunc arcu, vitae vehicula dolor tincidunt vel. Suspendisse a quam diam.\n\n' +
68
- 'Mauris a maximus libero. Ut blandit, leo in mollis condimentum, tortor massa bibendum est, ac porttitor neque felis tempus magna. Proin at nulla quis turpis laoreet posuere. Aenean at nunc nec sapien maximus viverra sed at tellus. Phasellus condimentum, leo at aliquam elementum, metus libero aliquet mi, in rutrum mauris odio ut nisl. Vivamus dignissim elit semper libero elementum, id tristique turpis eleifend. Phasellus quis erat tincidunt, luctus eros ac, vestibulum ante. Vestibulum non erat libero. Sed a risus vel enim lobortis commodo. Fusce viverra diam et nulla fermentum, vel consectetur ante accumsan. Duis lorem mi, ornare eget erat vel, ultricies finibus enim. Vivamus eget tortor sit amet nisi feugiat porta. Aliquam ullamcorper, ex non placerat euismod, sapien augue pellentesque ante, nec ullamcorper magna est a lacus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Maecenas et purus nunc. Pellentesque vel ante neque.\n\n' +
69
- 'Cras rutrum a lectus sit amet ultrices. Sed a enim dolor. Cras condimentum semper ex, in cursus dui fringilla et. Sed fringilla semper luctus. Praesent vel molestie dui. Nullam efficitur nec ligula id auctor. Integer vitae semper erat, quis sollicitudin arcu. Nulla tellus tortor, imperdiet sit amet facilisis gravida, porttitor ut massa. Duis egestas imperdiet felis vel dapibus. Maecenas vulputate tempus orci non accumsan.\n\n' +
70
- 'Integer diam ex, consequat et leo a, sagittis dignissim ante. Integer massa massa, dapibus at urna quis, vehicula facilisis mauris. Phasellus blandit neque enim. Suspendisse a lobortis sapien. Phasellus eget tellus fermentum, vestibulum nunc non, finibus sem. Aliquam sollicitudin risus non maximus pellentesque. Praesent mollis nisl vitae velit sodales vulputate. Cras vel quam quis ipsum rutrum luctus eu vel erat. Aenean efficitur viverra sapien vitae faucibus. Cras pretium ante ultrices ex varius accumsan. Nullam metus ante, dignissim ac justo in, condimentum sodales nibh. Nulla convallis justo laoreet massa vestibulum, consequat maximus risus suscipit. Proin ultrices elit velit, id tempor neque luctus in. Curabitur gravida ac ipsum sed efficitur. Ut accumsan ex dui, eget accumsan sem commodo vel.\n\n' +
71
- 'Proin nulla nisi, ullamcorper in mollis vel, malesuada at orci. Mauris vel enim pharetra, auctor mauris in, malesuada nulla. Nulla eu velit mauris. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin arcu sem, lacinia sit amet nibh interdum, aliquam sagittis est. Vivamus sed ex sed ligula tempor luctus id ut sapien. In tincidunt aliquet dolor nec placerat. Suspendisse non sodales sem, vitae convallis nisl. In id malesuada neque, ac lacinia nulla. Proin ultrices libero at tortor facilisis, eget dapibus dui imperdiet. Praesent vitae ullamcorper dolor. Morbi fringilla condimentum dolor, porttitor gravida leo condimentum at. Nam id diam vel sem dapibus vulputate. Proin ipsum enim, venenatis id mattis a, tincidunt a dolor. Ut risus ex, molestie ac ante non, accumsan laoreet felis.\n\n' +
72
- 'Cras vehicula velit sit amet varius ultrices. Sed rutrum ornare dolor. Maecenas ut nisl erat. Morbi molestie nulla eu massa dictum sagittis. Curabitur eu ipsum dolor. Phasellus at tristique ipsum. Fusce a maximus nunc. Nullam a maximus dolor, in vulputate mi.\n\n' +
73
- 'Ut et ligula ultricies, consectetur felis in, maximus libero. Quisque suscipit fringilla quam eu blandit. In ac ornare velit. Integer in pretium ligula. Nunc egestas id augue ac pharetra. Curabitur vel lorem semper, lacinia mi nec, rhoncus augue. Proin efficitur, quam ac tempus aliquam, augue mauris sagittis dui, eu bibendum dui dui sit amet nisi. Nullam mattis, erat nec pellentesque eleifend, risus dui dapibus nulla, ac efficitur eros libero sed ex. Duis venenatis blandit consectetur. Integer vulputate sem in quam ornare suscipit. Maecenas maximus ullamcorper posuere. Phasellus eleifend auctor dui eget luctus. Ut eleifend felis mauris, vitae congue dui accumsan vitae.\n\n' +
74
- 'Sed lobortis mollis purus, sed egestas orci tincidunt nec. Nunc vel varius nisl. Mauris molestie nibh et commodo pharetra. Pellentesque et ante nisi. Mauris id massa et enim tristique commodo eu in orci. In volutpat augue a nisl elementum mollis. Donec ex dui, bibendum vitae maximus non, lobortis ut odio. Suspendisse nulla massa, tincidunt in lacinia ornare, faucibus eu magna. Vestibulum sollicitudin, ex ultrices consectetur maximus, enim tellus facilisis sapien, a molestie orci ex non tortor. Morbi sit amet vulputate eros. Maecenas tempor orci at ligula interdum cursus.\n\n' +
75
- 'Praesent feugiat convallis rhoncus. Proin tristique eleifend dolor, sit amet tincidunt turpis tincidunt sed. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus luctus iaculis velit vel rutrum. Interdum et malesuada fames ac ante ipsum primis in faucibus. Vivamus risus nunc, varius non nunc sit amet, tincidunt convallis lacus. Mauris non lectus vitae libero imperdiet fermentum. In pellentesque dui at elit hendrerit, a sodales justo posuere. Ut rutrum lacus vitae egestas porttitor.\n\n' +
76
- 'Phasellus viverra condimentum tortor quis volutpat. Aenean lobortis vulputate libero non cursus. Vestibulum tincidunt condimentum ante eget tincidunt. Curabitur vel nunc id lacus efficitur feugiat. Aliquam a molestie quam, tempor varius ligula. Mauris lobortis nulla vel elit rhoncus, a varius sapien bibendum. Aenean in euismod metus. Fusce hendrerit mattis pellentesque. Aliquam erat volutpat. Nunc felis nisi, laoreet in dignissim sed, iaculis ut massa. Mauris varius mi nisi. Curabitur eu ante pulvinar, blandit arcu vitae, accumsan elit. In sit amet est tincidunt, laoreet nunc eu, facilisis nibh. Nullam molestie, turpis in lobortis molestie, sapien justo tincidunt velit, et viverra dui nibh vitae quam. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.\n\n' +
77
- 'Morbi vitae condimentum urna, sit amet mattis felis. Nam bibendum ante quis mi luctus viverra sit amet et eros. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis viverra leo nec justo vehicula, eu aliquam metus elementum. Ut ullamcorper libero ut ex hendrerit, ut ullamcorper sem venenatis. Etiam aliquam quam ac rhoncus facilisis. Integer et ligula bibendum, luctus arcu nec, congue diam. Donec fringilla augue eu molestie elementum. Duis consequat velit dolor, in elementum urna imperdiet a.\n\n' +
78
- 'Aliquam bibendum ipsum magna, at aliquam nisi ornare congue. Cras mollis libero justo, eget mattis velit commodo non. Nam sollicitudin dapibus feugiat. Integer condimentum odio vitae volutpat laoreet. Duis et odio diam. Sed ullamcorper eleifend erat. Duis magna odio, volutpat eu rhoncus vitae, malesuada id sem. Pellentesque ullamcorper libero nisl, eget vehicula orci iaculis sed.\n\n' +
79
- 'Proin dolor quam, fermentum in sem vel, elementum convallis nibh. Quisque vitae eros eu risus euismod accumsan quis non dui. Praesent vestibulum, ex ut pharetra tincidunt, neque sem sagittis nisl, ut iaculis justo mi non diam. Pellentesque eu elit id ante aliquet ullamcorper. Maecenas posuere, quam non aliquam finibus, metus neque maximus nibh, sed sodales est odio nec leo. Donec at leo dictum, condimentum odio eleifend, sollicitudin enim. Sed suscipit auctor sagittis. Proin eu efficitur dolor, nec vestibulum odio. In egestas sollicitudin semper.\n\n' +
80
- 'Fusce a sapien at dui commodo fermentum eget sed tortor. Sed eu fringilla ipsum. Nulla nec dictum neque. Vivamus sed tempor libero. Pellentesque eget eleifend ante, eu posuere erat. Donec placerat turpis a nisi congue, in convallis tellus feugiat. Aliquam hendrerit vulputate nunc, in dictum augue ultrices id. Cras facilisis sapien sit amet dignissim efficitur. Donec a est sit amet ante tempor sodales. Donec aliquam odio dui, quis aliquet nulla placerat dapibus. Donec porttitor est ut dolor bibendum consequat. Duis maximus tortor velit.\n\n' +
81
- 'Maecenas ut elit sem. Maecenas at arcu id augue laoreet mollis id a turpis. Nullam iaculis facilisis quam, nec auctor metus volutpat sit amet. Maecenas quis feugiat tortor. Nam malesuada placerat cursus. Duis sed augue et risus viverra fermentum vel quis nunc. Nulla dignissim, ante eu luctus viverra, lorem elit ultricies tellus, in consectetur turpis est vel nulla. Sed pulvinar laoreet mi quis varius. Nulla fermentum, dui ac dictum scelerisque, libero mi semper tellus, vel volutpat ante diam et urna. Etiam feugiat nisi id risus imperdiet ullamcorper. Morbi eget fermentum ipsum. Mauris mi nunc, interdum eget ante et, pharetra aliquam eros. Donec at porttitor mauris. Etiam euismod libero vitae nibh convallis tristique.\n\n' +
82
- 'Quisque congue nulla eros. Vestibulum maximus erat ac turpis viverra, id tincidunt elit hendrerit. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Quisque laoreet augue ut dolor aliquet elementum. In bibendum in mauris sit amet volutpat. Etiam vulputate lectus et ultrices faucibus. Pellentesque est massa, vestibulum at malesuada et, dignissim ac sem. Donec a lacus lacinia, sollicitudin leo id, tristique tortor. Morbi pellentesque enim non arcu lobortis, et rhoncus nibh euismod. Ut faucibus, nulla vestibulum porta egestas, sem ante molestie libero, ac fermentum augue turpis at ipsum. Nullam fermentum turpis vel malesuada rhoncus. Vestibulum eget nisl maximus, tempus mauris et, vestibulum magna.\n\n' +
83
- 'Fusce bibendum metus vel libero pretium eleifend. Proin libero orci, rhoncus sed neque ac, finibus dignissim erat. Nullam at mollis purus. Praesent vel auctor sem. Praesent nec nibh at elit ullamcorper placerat. Proin pellentesque orci ut risus egestas vehicula. Mauris blandit convallis venenatis.\n\n' +
84
- 'Cras eget imperdiet elit. Donec in felis sagittis, maximus nunc at, commodo tellus. Praesent molestie fringilla neque, nec pharetra quam aliquet ac. Sed luctus sollicitudin ante, non tempus augue ornare quis. Etiam hendrerit metus ac ipsum sollicitudin, id sodales urna volutpat. Praesent cursus finibus arcu, quis pulvinar metus mollis quis. Suspendisse in enim velit. Etiam id dolor dolor. Integer fringilla ligula ultricies, tempor leo quis, luctus nisi. Mauris quis malesuada enim. In rhoncus elementum viverra. Quisque maximus lorem sit amet molestie congue. Phasellus ut eleifend lectus. Vestibulum aliquet urna ex, sit amet cursus orci mollis ut.\n\n' +
85
- 'Sed quis aliquam urna. Integer velit sem, consequat eu fermentum eu, hendrerit sit amet mi. Nulla congue risus vel finibus consequat. Proin ornare ornare vestibulum. Aliquam varius blandit nisl, vel commodo sem sollicitudin in. Integer non consectetur purus, sit amet volutpat est. Curabitur vitae enim leo. Quisque sodales pharetra lorem, non venenatis urna luctus vel.\n\n' +
86
- 'Nulla ac magna tempus, sollicitudin nibh vitae, suscipit velit. Aliquam ultrices erat blandit velit varius, vel ullamcorper orci lacinia. Ut fermentum magna eget turpis consequat convallis. Duis blandit rhoncus cursus. Curabitur rhoncus leo vel scelerisque porttitor. Pellentesque posuere nisi tincidunt, dapibus ipsum eu, elementum lacus. Praesent condimentum gravida ex, et auctor odio maximus eu. Praesent in velit nec sem rhoncus congue at eget lorem. Proin vitae erat lacus.';
87
- export const generateLoremIpsum = (length) => {
88
- length = Math.max(Math.min(11801, length), 0);
89
- return loremIpsum.substring(0, length);
90
- };
package/utils/tools.d.ts CHANGED
@@ -124,3 +124,9 @@ export type KeyBinder<K extends string, Type> = {
124
124
  * @returns Locked function that prevents concurrent execution
125
125
  */
126
126
  export declare function createLockedAsyncFunction(fn: () => Promise<void>): () => void;
127
+ /**
128
+ * Converts a base64 data URL to a Blob.
129
+ * @param imageAsBase64 - Data URL (e.g. "data:image/png;base64,...") or base64 string
130
+ * @returns Promise resolving to the Blob
131
+ */
132
+ export declare function base64ToBlob(imageAsBase64: string): Promise<Blob>;
package/utils/tools.js CHANGED
@@ -173,3 +173,11 @@ export function createLockedAsyncFunction(fn) {
173
173
  });
174
174
  };
175
175
  }
176
+ /**
177
+ * Converts a base64 data URL to a Blob.
178
+ * @param imageAsBase64 - Data URL (e.g. "data:image/png;base64,...") or base64 string
179
+ * @returns Promise resolving to the Blob
180
+ */
181
+ export async function base64ToBlob(imageAsBase64) {
182
+ return (await fetch(imageAsBase64)).blob();
183
+ }
package/utils/types.d.ts CHANGED
@@ -292,15 +292,6 @@ export type AuditBy = {
292
292
  /** Timestamp of the change */
293
293
  auditAt: Timestamp;
294
294
  };
295
- /**
296
- * Simplified audit information (v2).
297
- *
298
- * Only stores the auditor ID, not full audit details.
299
- */
300
- export type AuditableV2 = {
301
- /** ID of the user/system that made the change */
302
- _auditorId: string;
303
- };
304
295
  /**
305
296
  * Timestamp with formatted string representation.
306
297
  */
@@ -16,7 +16,7 @@ import { ArrayType, AuditBy, RangeTimestamp, TypedMap } from '../utils/types.js'
16
16
  * @param mandatory - Whether the object itself is required (default: true)
17
17
  * @returns Validator that validates both keys and values
18
18
  */
19
- export declare const tsValidateDynamicObject: <T extends object>(valuesValidator: ValidatorTypeResolver<T[keyof T]>, keysValidator: ValidatorTypeResolver<string>, mandatory?: boolean) => (import("./validator-core.js").ValidatorImpl<any> | ((input?: T) => InvalidResultObject<T> | undefined))[];
19
+ export declare const tsValidateDynamicObject: <T extends object>(valuesValidator: ValidatorTypeResolver<T[keyof T]>, keysValidator: ValidatorTypeResolver<keyof T>, mandatory?: boolean) => (import("./validator-core.js").ValidatorImpl<any> | ((input?: T) => InvalidResultObject<T> | undefined))[];
20
20
  /**
21
21
  * Validates input against multiple validators (union type).
22
22
  *
@@ -10,7 +10,7 @@ import { CustomException } from '../core/exceptions/exceptions.js';
10
10
  *
11
11
  * This enables type-safe validation where the validator structure matches the data structure.
12
12
  */
13
- export type ValidatorTypeResolver<K> = K extends [any] ? Validator<K> : K extends [any, any] ? Validator<K> : K extends [any, any, any] ? Validator<K> : K extends [any, any, any, any] ? Validator<K> : K extends any[] ? Validator<K> : K extends TS_Object ? TypeValidator<K> | Validator<K> : Validator<K>;
13
+ export type ValidatorTypeResolver<K> = K extends (any[] | readonly any[]) ? Validator<K> : K extends TS_Object ? TypeValidator<K> | Validator<K> : Validator<K>;
14
14
  /**
15
15
  * Core validator function type.
16
16
  *
@@ -1,5 +1,5 @@
1
1
  import { Validator, ValidatorTypeResolver } from './validator-core.js';
2
- import { AuditableV2, DBPointer } from '../utils/types.js';
2
+ import { DBPointer } from '../utils/types.js';
3
3
  import { DBDef_V3 } from '../db/types.js';
4
4
  /**
5
5
  * Validates an optional array (non-mandatory).
@@ -111,7 +111,6 @@ export declare const tsValidator_LowerUpperStringWithSpaces: Validator<string>;
111
111
  export declare const tsValidator_LowerUpperStringWithDashesAndUnderscore: Validator<string>;
112
112
  export declare const tsValidator_InternationalPhoneNumber: Validator<string>;
113
113
  export declare const tsValidator_DB_RefId: Validator<string>;
114
- export declare const tsValidator_AuditableV2: ValidatorTypeResolver<AuditableV2>;
115
114
  export declare const DB_Object_validator: {
116
115
  __metadata1: import("./validator-core.js").ValidatorImpl<any>;
117
116
  _id: Validator<string>;
@@ -118,7 +118,6 @@ export const tsValidator_LowerUpperStringWithSpaces = tsValidateRegexp(/^[A-Za-z
118
118
  export const tsValidator_LowerUpperStringWithDashesAndUnderscore = tsValidateRegexp(/^[A-Za-z-_]+$/);
119
119
  export const tsValidator_InternationalPhoneNumber = tsValidateRegexp(/^\+(?:[0-9] ?){6,14}[0-9]$/);
120
120
  export const tsValidator_DB_RefId = tsValidateId(dbRefIdLength);
121
- export const tsValidator_AuditableV2 = { _auditorId: tsValidateString() };
122
121
  export const DB_Object_validator = {
123
122
  // this will be the way to handle app level context via proto.. need to rename this to __metadata once done
124
123
  __metadata1: tsValidateOptional,