@digital-alchemy/core 26.2.17 → 26.5.1
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/CLAUDE.md +302 -0
- package/README.md +19 -3
- package/dist/helpers/async.d.mts +37 -0
- package/dist/helpers/async.mjs +50 -15
- package/dist/helpers/async.mjs.map +1 -1
- package/dist/helpers/config-environment-loader.d.mts +39 -0
- package/dist/helpers/config-environment-loader.mjs +51 -11
- package/dist/helpers/config-environment-loader.mjs.map +1 -1
- package/dist/helpers/config-file-loader.d.mts +65 -0
- package/dist/helpers/config-file-loader.mjs +80 -4
- package/dist/helpers/config-file-loader.mjs.map +1 -1
- package/dist/helpers/config.d.mts +202 -5
- package/dist/helpers/config.mjs +60 -0
- package/dist/helpers/config.mjs.map +1 -1
- package/dist/helpers/context.d.mts +12 -1
- package/dist/helpers/cron.d.mts +154 -7
- package/dist/helpers/cron.mjs +47 -4
- package/dist/helpers/cron.mjs.map +1 -1
- package/dist/helpers/errors.d.mts +45 -0
- package/dist/helpers/errors.mjs +45 -0
- package/dist/helpers/errors.mjs.map +1 -1
- package/dist/helpers/events.d.mts +23 -0
- package/dist/helpers/events.mjs +23 -0
- package/dist/helpers/events.mjs.map +1 -1
- package/dist/helpers/extend.d.mts +50 -0
- package/dist/helpers/extend.mjs +63 -0
- package/dist/helpers/extend.mjs.map +1 -1
- package/dist/helpers/index.d.mts +9 -0
- package/dist/helpers/index.mjs +9 -0
- package/dist/helpers/index.mjs.map +1 -1
- package/dist/helpers/lifecycle.d.mts +102 -16
- package/dist/helpers/lifecycle.mjs +19 -1
- package/dist/helpers/lifecycle.mjs.map +1 -1
- package/dist/helpers/logger.d.mts +178 -17
- package/dist/helpers/logger.mjs +41 -1
- package/dist/helpers/logger.mjs.map +1 -1
- package/dist/helpers/module.d.mts +110 -0
- package/dist/helpers/module.mjs +55 -6
- package/dist/helpers/module.mjs.map +1 -1
- package/dist/helpers/service-runner.d.mts +27 -1
- package/dist/helpers/service-runner.mjs +27 -1
- package/dist/helpers/service-runner.mjs.map +1 -1
- package/dist/helpers/utilities.d.mts +123 -3
- package/dist/helpers/utilities.mjs +110 -3
- package/dist/helpers/utilities.mjs.map +1 -1
- package/dist/helpers/wiring.d.mts +385 -0
- package/dist/helpers/wiring.mjs +120 -0
- package/dist/helpers/wiring.mjs.map +1 -1
- package/dist/services/als.service.d.mts +10 -0
- package/dist/services/als.service.mjs +49 -0
- package/dist/services/als.service.mjs.map +1 -1
- package/dist/services/configuration.service.d.mts +22 -0
- package/dist/services/configuration.service.mjs +140 -12
- package/dist/services/configuration.service.mjs.map +1 -1
- package/dist/services/index.d.mts +8 -0
- package/dist/services/index.mjs +8 -0
- package/dist/services/index.mjs.map +1 -1
- package/dist/services/internal.service.d.mts +98 -19
- package/dist/services/internal.service.mjs +91 -9
- package/dist/services/internal.service.mjs.map +1 -1
- package/dist/services/is.service.d.mts +64 -4
- package/dist/services/is.service.mjs +67 -4
- package/dist/services/is.service.mjs.map +1 -1
- package/dist/services/lifecycle.service.d.mts +26 -0
- package/dist/services/lifecycle.service.mjs +67 -9
- package/dist/services/lifecycle.service.mjs.map +1 -1
- package/dist/services/logger.service.d.mts +27 -0
- package/dist/services/logger.service.mjs +133 -9
- package/dist/services/logger.service.mjs.map +1 -1
- package/dist/services/scheduler.service.d.mts +19 -0
- package/dist/services/scheduler.service.mjs +87 -4
- package/dist/services/scheduler.service.mjs.map +1 -1
- package/dist/services/wiring.service.d.mts +28 -0
- package/dist/services/wiring.service.mjs +152 -19
- package/dist/services/wiring.service.mjs.map +1 -1
- package/dist/testing/index.d.mts +4 -0
- package/dist/testing/index.mjs +4 -0
- package/dist/testing/index.mjs.map +1 -1
- package/dist/testing/mock-logger.d.mts +8 -0
- package/dist/testing/mock-logger.mjs +9 -0
- package/dist/testing/mock-logger.mjs.map +1 -1
- package/dist/testing/test-module.d.mts +107 -27
- package/dist/testing/test-module.mjs +58 -1
- package/dist/testing/test-module.mjs.map +1 -1
- package/package.json +33 -31
|
@@ -11,27 +11,82 @@ export type RemoveCallback = {
|
|
|
11
11
|
remove: () => void;
|
|
12
12
|
(): void;
|
|
13
13
|
};
|
|
14
|
+
/**
|
|
15
|
+
* Stateless utility bag attached to every `InternalDefinition` instance.
|
|
16
|
+
*
|
|
17
|
+
* @remarks
|
|
18
|
+
* Holds the global `EventEmitter`, the `is` type-guard singleton, and helpers
|
|
19
|
+
* for date math, object path operations, and string formatting.
|
|
20
|
+
* Constructed once per bootstrap cycle; replaced on teardown via a fresh
|
|
21
|
+
* `InternalDefinition`.
|
|
22
|
+
*/
|
|
14
23
|
export declare class InternalUtils {
|
|
15
24
|
/**
|
|
16
|
-
* The global eventemitter. All of `@digital-alchemy` will be wired through this
|
|
25
|
+
* The global eventemitter. All of `@digital-alchemy` will be wired through this.
|
|
17
26
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
27
|
+
* @remarks
|
|
28
|
+
* Bootstrapping process will initialize this at boot and clean it up at
|
|
29
|
+
* teardown. Making listener changes should only be done from within the
|
|
30
|
+
* context of service functions.
|
|
20
31
|
*/
|
|
21
32
|
event: EventEmitter;
|
|
22
33
|
/**
|
|
23
|
-
*
|
|
34
|
+
* Reference to the `is` type-guard singleton importable from `core`.
|
|
24
35
|
*/
|
|
25
36
|
is: IsIt;
|
|
26
37
|
constructor();
|
|
38
|
+
/**
|
|
39
|
+
* Convert a `camelCase`, `snake_case`, or `kebab-case` string to `Title Case`.
|
|
40
|
+
*/
|
|
27
41
|
titleCase(input: string): string;
|
|
42
|
+
/**
|
|
43
|
+
* Compute the target `Dayjs` moment when an offset will elapse.
|
|
44
|
+
*/
|
|
28
45
|
getIntervalTarget(offset: TOffset): Dayjs;
|
|
46
|
+
/**
|
|
47
|
+
* Resolve a `TOffset` value to milliseconds.
|
|
48
|
+
*/
|
|
29
49
|
getIntervalMs(offset: TOffset): number;
|
|
50
|
+
/**
|
|
51
|
+
* Format the elapsed time between two dates as a human-readable relative string.
|
|
52
|
+
*
|
|
53
|
+
* @remarks
|
|
54
|
+
* Iterates unit buckets from largest (year) to smallest (second) and returns
|
|
55
|
+
* the first unit whose cutoff is exceeded. Falls back to "second" when the
|
|
56
|
+
* difference is less than one minute so there is always a non-empty result.
|
|
57
|
+
*
|
|
58
|
+
* @throws {Error} if either date argument cannot be parsed by `dayjs`.
|
|
59
|
+
*/
|
|
30
60
|
relativeDate(pastDate: inputFormats, futureDate?: inputFormats): string;
|
|
61
|
+
/**
|
|
62
|
+
* Dot-path object utilities: `get`, `set`, `del`, and `deepExtend`.
|
|
63
|
+
*
|
|
64
|
+
* @remarks
|
|
65
|
+
* Used throughout core to read and write nested configuration paths like
|
|
66
|
+
* `"boilerplate.LOG_LEVEL"` without assuming the intermediate objects exist.
|
|
67
|
+
*/
|
|
31
68
|
object: {
|
|
32
69
|
deepExtend: typeof deepExtend;
|
|
70
|
+
/**
|
|
71
|
+
* Delete the value at `path` within `object`. Silently no-ops if any
|
|
72
|
+
* intermediate key does not exist.
|
|
73
|
+
*/
|
|
33
74
|
del<T>(object: T, path: string): void;
|
|
75
|
+
/**
|
|
76
|
+
* Read the value at `path` within `object`. Returns `undefined` if any
|
|
77
|
+
* intermediate key is missing.
|
|
78
|
+
*/
|
|
34
79
|
get<T, P extends string>(object: T, path: P): Get<T, P>;
|
|
80
|
+
/**
|
|
81
|
+
* Write `value` at `path` within `object`, creating intermediate objects
|
|
82
|
+
* as needed.
|
|
83
|
+
*
|
|
84
|
+
* @remarks
|
|
85
|
+
* When `doNotReplace` is true the write is skipped if the key already
|
|
86
|
+
* has a value — useful for applying defaults without overwriting explicit config.
|
|
87
|
+
*
|
|
88
|
+
* @throws {Error} if an intermediate path segment resolves to a non-object.
|
|
89
|
+
*/
|
|
35
90
|
set<T>(object: T, path: string, value: unknown, doNotReplace?: boolean): void;
|
|
36
91
|
};
|
|
37
92
|
}
|
|
@@ -40,51 +95,64 @@ type SafeExecOptions = {
|
|
|
40
95
|
exec: () => TBlackHole;
|
|
41
96
|
};
|
|
42
97
|
type Phase = "bootstrap" | "teardown" | "running";
|
|
98
|
+
/**
|
|
99
|
+
* Bootstrap-scoped state container passed as `internal` into every service.
|
|
100
|
+
*
|
|
101
|
+
* @remarks
|
|
102
|
+
* Created fresh on each `bootstrap()` call and torn down with the application.
|
|
103
|
+
* Holds the boot-time module registry (`loadedModules`, `moduleMappings`),
|
|
104
|
+
* the lifecycle event bus, references to boilerplate service APIs, and the
|
|
105
|
+
* `InternalUtils` helper bag.
|
|
106
|
+
*
|
|
107
|
+
* Downstream code should treat `internal` as read-only except for the
|
|
108
|
+
* documented mutation points (`safeExec`, `removeFn`, explicit setters on
|
|
109
|
+
* `boot.*`).
|
|
110
|
+
*/
|
|
43
111
|
export declare class InternalDefinition {
|
|
44
112
|
/**
|
|
45
|
-
* Utility methods provided by boilerplate
|
|
113
|
+
* Utility methods provided by boilerplate.
|
|
46
114
|
*/
|
|
47
115
|
boilerplate: Pick<GetApis<typeof LIB_BOILERPLATE>, "configuration" | "logger">;
|
|
48
116
|
/**
|
|
49
|
-
*
|
|
117
|
+
* Alias for `internal.boilerplate.configuration`.
|
|
50
118
|
*/
|
|
51
119
|
config: GetApis<typeof LIB_BOILERPLATE>["configuration"];
|
|
52
120
|
boot: {
|
|
53
121
|
/**
|
|
54
|
-
* Options that were passed into bootstrap
|
|
122
|
+
* Options that were passed into bootstrap.
|
|
55
123
|
*/
|
|
56
124
|
options: BootstrapOptions;
|
|
57
125
|
/**
|
|
58
|
-
* Application that was bootstrapped
|
|
126
|
+
* Application that was bootstrapped.
|
|
59
127
|
*/
|
|
60
128
|
application: ApplicationDefinition<ServiceMap, OptionalModuleConfiguration>;
|
|
61
129
|
/**
|
|
62
|
-
* Lifecycle events that have completed
|
|
130
|
+
* Lifecycle events that have completed.
|
|
63
131
|
*/
|
|
64
132
|
completedLifecycleEvents: Set<LifecycleStages>;
|
|
65
133
|
/**
|
|
66
|
-
*
|
|
134
|
+
* Internal lifecycle event bus; services attach hooks via the injected `lifecycle` param.
|
|
67
135
|
*/
|
|
68
136
|
lifecycle: ReturnType<typeof CreateLifecycle>;
|
|
69
137
|
/**
|
|
70
|
-
* Roughly speaking, what
|
|
138
|
+
* Roughly speaking, what is the application doing? Mostly useful for debugging.
|
|
71
139
|
*/
|
|
72
140
|
phase: Phase;
|
|
73
141
|
/**
|
|
74
|
-
*
|
|
142
|
+
* Association of project names to `{ service: DeclarationFunction }`.
|
|
75
143
|
*/
|
|
76
144
|
moduleMappings: Map<string, TModuleMappings>;
|
|
77
145
|
/**
|
|
78
|
-
*
|
|
146
|
+
* Association of project names to `{ service: InitializedService }`.
|
|
79
147
|
*/
|
|
80
148
|
loadedModules: Map<string, TResolvedModuleMappings>;
|
|
81
149
|
/**
|
|
82
|
-
*
|
|
150
|
+
* Simple list of modules that have their construction phase complete.
|
|
83
151
|
*/
|
|
84
152
|
constructComplete: Set<string>;
|
|
85
153
|
startup: Date;
|
|
86
154
|
/**
|
|
87
|
-
* Service construction times in order
|
|
155
|
+
* Service construction times in order.
|
|
88
156
|
*/
|
|
89
157
|
serviceConstructionTimes: Array<{
|
|
90
158
|
module: string;
|
|
@@ -92,23 +160,34 @@ export declare class InternalDefinition {
|
|
|
92
160
|
duration: string;
|
|
93
161
|
}>;
|
|
94
162
|
/**
|
|
95
|
-
* Config loader execution times
|
|
163
|
+
* Config loader execution times.
|
|
96
164
|
*/
|
|
97
165
|
configTimings?: Record<string, string>;
|
|
98
166
|
};
|
|
99
167
|
utils: InternalUtils;
|
|
100
168
|
/**
|
|
169
|
+
* Wrap a remove callback so it can be called directly or via `{ remove }` destructuring.
|
|
101
170
|
*
|
|
171
|
+
* @remarks
|
|
172
|
+
* Accommodates callers that prefer either:
|
|
102
173
|
* ```typescript
|
|
103
|
-
* // Is it
|
|
104
174
|
* const remove = doThing();
|
|
105
175
|
* // or
|
|
106
176
|
* const { remove } = doThing();
|
|
107
177
|
* ```
|
|
108
|
-
*
|
|
109
|
-
* Now it's both! Inconsistency is the now supported
|
|
178
|
+
* Both styles are now supported; inconsistency between APIs is intentional.
|
|
110
179
|
*/
|
|
111
180
|
removeFn(remove: () => TBlackHole): RemoveCallback;
|
|
181
|
+
/**
|
|
182
|
+
* Execute a callback, swallowing and logging any thrown error.
|
|
183
|
+
*
|
|
184
|
+
* @remarks
|
|
185
|
+
* Used throughout scheduler and lifecycle code to ensure that a misbehaving
|
|
186
|
+
* user callback cannot crash the entire wiring engine. Errors are logged at
|
|
187
|
+
* `error` level with full context so they remain visible without being fatal.
|
|
188
|
+
* Returns `undefined` on any error path so callers can treat the return type
|
|
189
|
+
* as optional without extra null-checks.
|
|
190
|
+
*/
|
|
112
191
|
safeExec<T>(options: (() => TBlackHole) | SafeExecOptions): Promise<T>;
|
|
113
192
|
}
|
|
114
193
|
export {};
|
|
@@ -18,22 +18,38 @@ const formatter = new Intl.RelativeTimeFormat("en", {
|
|
|
18
18
|
style: "short",
|
|
19
19
|
});
|
|
20
20
|
// #MARK: misc
|
|
21
|
+
/**
|
|
22
|
+
* Stateless utility bag attached to every `InternalDefinition` instance.
|
|
23
|
+
*
|
|
24
|
+
* @remarks
|
|
25
|
+
* Holds the global `EventEmitter`, the `is` type-guard singleton, and helpers
|
|
26
|
+
* for date math, object path operations, and string formatting.
|
|
27
|
+
* Constructed once per bootstrap cycle; replaced on teardown via a fresh
|
|
28
|
+
* `InternalDefinition`.
|
|
29
|
+
*/
|
|
21
30
|
export class InternalUtils {
|
|
22
31
|
/**
|
|
23
|
-
* The global eventemitter. All of `@digital-alchemy` will be wired through this
|
|
32
|
+
* The global eventemitter. All of `@digital-alchemy` will be wired through this.
|
|
24
33
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
34
|
+
* @remarks
|
|
35
|
+
* Bootstrapping process will initialize this at boot and clean it up at
|
|
36
|
+
* teardown. Making listener changes should only be done from within the
|
|
37
|
+
* context of service functions.
|
|
27
38
|
*/
|
|
28
39
|
event;
|
|
29
40
|
/**
|
|
30
|
-
*
|
|
41
|
+
* Reference to the `is` type-guard singleton importable from `core`.
|
|
31
42
|
*/
|
|
32
43
|
is;
|
|
33
44
|
constructor() {
|
|
45
|
+
// unlimited listeners because every service may register lifecycle callbacks,
|
|
46
|
+
// and the default of 10 would fire spurious MaxListenersExceededWarnings
|
|
34
47
|
this.event = new EventEmitter();
|
|
35
48
|
this.event.setMaxListeners(NONE);
|
|
36
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Convert a `camelCase`, `snake_case`, or `kebab-case` string to `Title Case`.
|
|
52
|
+
*/
|
|
37
53
|
titleCase(input) {
|
|
38
54
|
const matches = input.match(new RegExp("[a-z][A-Z]", "g"));
|
|
39
55
|
if (matches) {
|
|
@@ -44,14 +60,30 @@ export class InternalUtils {
|
|
|
44
60
|
.map(word => `${word.charAt(FIRST).toUpperCase()}${word.slice(EVERYTHING_ELSE)}`)
|
|
45
61
|
.join(" ");
|
|
46
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Compute the target `Dayjs` moment when an offset will elapse.
|
|
65
|
+
*/
|
|
47
66
|
getIntervalTarget(offset) {
|
|
48
67
|
const duration = toOffsetDuration(offset);
|
|
49
68
|
const now = dayjs();
|
|
50
69
|
return duration ? now.add(duration) : now;
|
|
51
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Resolve a `TOffset` value to milliseconds.
|
|
73
|
+
*/
|
|
52
74
|
getIntervalMs(offset) {
|
|
53
75
|
return toOffsetMs(offset);
|
|
54
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Format the elapsed time between two dates as a human-readable relative string.
|
|
79
|
+
*
|
|
80
|
+
* @remarks
|
|
81
|
+
* Iterates unit buckets from largest (year) to smallest (second) and returns
|
|
82
|
+
* the first unit whose cutoff is exceeded. Falls back to "second" when the
|
|
83
|
+
* difference is less than one minute so there is always a non-empty result.
|
|
84
|
+
*
|
|
85
|
+
* @throws {Error} if either date argument cannot be parsed by `dayjs`.
|
|
86
|
+
*/
|
|
55
87
|
relativeDate(pastDate, futureDate = new Date().toISOString()) {
|
|
56
88
|
const past = dayjs(pastDate);
|
|
57
89
|
if (!past.isValid()) {
|
|
@@ -74,8 +106,19 @@ export class InternalUtils {
|
|
|
74
106
|
return out;
|
|
75
107
|
}
|
|
76
108
|
// #region .object
|
|
109
|
+
/**
|
|
110
|
+
* Dot-path object utilities: `get`, `set`, `del`, and `deepExtend`.
|
|
111
|
+
*
|
|
112
|
+
* @remarks
|
|
113
|
+
* Used throughout core to read and write nested configuration paths like
|
|
114
|
+
* `"boilerplate.LOG_LEVEL"` without assuming the intermediate objects exist.
|
|
115
|
+
*/
|
|
77
116
|
object = {
|
|
78
117
|
deepExtend,
|
|
118
|
+
/**
|
|
119
|
+
* Delete the value at `path` within `object`. Silently no-ops if any
|
|
120
|
+
* intermediate key does not exist.
|
|
121
|
+
*/
|
|
79
122
|
del(object, path) {
|
|
80
123
|
const keys = path.split(".");
|
|
81
124
|
let current = object; // Starting with the object as an unknown type
|
|
@@ -101,6 +144,10 @@ export class InternalUtils {
|
|
|
101
144
|
}
|
|
102
145
|
}
|
|
103
146
|
},
|
|
147
|
+
/**
|
|
148
|
+
* Read the value at `path` within `object`. Returns `undefined` if any
|
|
149
|
+
* intermediate key is missing.
|
|
150
|
+
*/
|
|
104
151
|
get(object, path) {
|
|
105
152
|
const keys = path.split(".");
|
|
106
153
|
let current = object;
|
|
@@ -112,6 +159,16 @@ export class InternalUtils {
|
|
|
112
159
|
}
|
|
113
160
|
return current;
|
|
114
161
|
},
|
|
162
|
+
/**
|
|
163
|
+
* Write `value` at `path` within `object`, creating intermediate objects
|
|
164
|
+
* as needed.
|
|
165
|
+
*
|
|
166
|
+
* @remarks
|
|
167
|
+
* When `doNotReplace` is true the write is skipped if the key already
|
|
168
|
+
* has a value — useful for applying defaults without overwriting explicit config.
|
|
169
|
+
*
|
|
170
|
+
* @throws {Error} if an intermediate path segment resolves to a non-object.
|
|
171
|
+
*/
|
|
115
172
|
set(object, path, value, doNotReplace = false) {
|
|
116
173
|
const keys = path.split(".");
|
|
117
174
|
let current = object; // Starting with the object as an unknown type
|
|
@@ -144,27 +201,41 @@ export class InternalUtils {
|
|
|
144
201
|
};
|
|
145
202
|
}
|
|
146
203
|
// #region Base definition
|
|
204
|
+
/**
|
|
205
|
+
* Bootstrap-scoped state container passed as `internal` into every service.
|
|
206
|
+
*
|
|
207
|
+
* @remarks
|
|
208
|
+
* Created fresh on each `bootstrap()` call and torn down with the application.
|
|
209
|
+
* Holds the boot-time module registry (`loadedModules`, `moduleMappings`),
|
|
210
|
+
* the lifecycle event bus, references to boilerplate service APIs, and the
|
|
211
|
+
* `InternalUtils` helper bag.
|
|
212
|
+
*
|
|
213
|
+
* Downstream code should treat `internal` as read-only except for the
|
|
214
|
+
* documented mutation points (`safeExec`, `removeFn`, explicit setters on
|
|
215
|
+
* `boot.*`).
|
|
216
|
+
*/
|
|
147
217
|
export class InternalDefinition {
|
|
148
218
|
/**
|
|
149
|
-
* Utility methods provided by boilerplate
|
|
219
|
+
* Utility methods provided by boilerplate.
|
|
150
220
|
*/
|
|
151
221
|
boilerplate;
|
|
152
222
|
/**
|
|
153
|
-
*
|
|
223
|
+
* Alias for `internal.boilerplate.configuration`.
|
|
154
224
|
*/
|
|
155
225
|
config;
|
|
156
226
|
boot;
|
|
157
227
|
utils = new InternalUtils();
|
|
158
228
|
/**
|
|
229
|
+
* Wrap a remove callback so it can be called directly or via `{ remove }` destructuring.
|
|
159
230
|
*
|
|
231
|
+
* @remarks
|
|
232
|
+
* Accommodates callers that prefer either:
|
|
160
233
|
* ```typescript
|
|
161
|
-
* // Is it
|
|
162
234
|
* const remove = doThing();
|
|
163
235
|
* // or
|
|
164
236
|
* const { remove } = doThing();
|
|
165
237
|
* ```
|
|
166
|
-
*
|
|
167
|
-
* Now it's both! Inconsistency is the now supported
|
|
238
|
+
* Both styles are now supported; inconsistency between APIs is intentional.
|
|
168
239
|
*/
|
|
169
240
|
removeFn(remove) {
|
|
170
241
|
const out = remove;
|
|
@@ -172,10 +243,21 @@ export class InternalDefinition {
|
|
|
172
243
|
return out;
|
|
173
244
|
}
|
|
174
245
|
// #MARK: safeExec
|
|
246
|
+
/**
|
|
247
|
+
* Execute a callback, swallowing and logging any thrown error.
|
|
248
|
+
*
|
|
249
|
+
* @remarks
|
|
250
|
+
* Used throughout scheduler and lifecycle code to ensure that a misbehaving
|
|
251
|
+
* user callback cannot crash the entire wiring engine. Errors are logged at
|
|
252
|
+
* `error` level with full context so they remain visible without being fatal.
|
|
253
|
+
* Returns `undefined` on any error path so callers can treat the return type
|
|
254
|
+
* as optional without extra null-checks.
|
|
255
|
+
*/
|
|
175
256
|
async safeExec(options) {
|
|
176
257
|
const logger = this.boilerplate.logger.systemLogger;
|
|
177
258
|
const context = is.function(options) ? undefined : options?.context;
|
|
178
259
|
const exec = is.function(options) ? options : options?.exec;
|
|
260
|
+
// a non-function exec is a programming error, not a runtime error; log and bail
|
|
179
261
|
if (!is.function(exec)) {
|
|
180
262
|
logger.error({ context }, `received non-function callback to [safeExec]`);
|
|
181
263
|
return undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"internal.service.mjs","sourceRoot":"","sources":["../../src/services/internal.service.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,KAAK,MAAM,OAAO,CAAC;AAgB1B,OAAO,EACL,YAAY,EACZ,GAAG,EACH,UAAU,EACV,KAAK,EACL,IAAI,EACJ,MAAM,EACN,IAAI,EACJ,MAAM,EACN,KAAK,EACL,gBAAgB,EAChB,UAAU,EACV,IAAI,GACL,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAItC,MAAM,eAAe,GAAG,CAAC,CAAC;AAC1B,MAAM,MAAM,GAAG,EAAE,CAAC;AAElB,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAsC;IACvE,CAAC,MAAM,EAAE,IAAI,CAAC;IACd,CAAC,OAAO,EAAE,IAAI,GAAG,MAAM,CAAC;IACxB,CAAC,KAAK,EAAE,GAAG,CAAC;IACZ,CAAC,MAAM,EAAE,IAAI,CAAC;IACd,CAAC,QAAQ,EAAE,MAAM,CAAC;IAClB,CAAC,QAAQ,EAAE,MAAM,CAAC;CACnB,CAAC,CAAC;AAKH,+CAA+C;AAC/C,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,kBAAkB,CAAC,IAAI,EAAE;IAClD,OAAO,EAAE,MAAM;IACf,KAAK,EAAE,OAAO;CACf,CAAC,CAAC;AAEH,cAAc;AACd,MAAM,OAAO,aAAa;IACxB
|
|
1
|
+
{"version":3,"file":"internal.service.mjs","sourceRoot":"","sources":["../../src/services/internal.service.mts"],"names":[],"mappings":"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"}
|
|
@@ -3,33 +3,93 @@ import type { TBlackHole, TContext } from "../index.mts";
|
|
|
3
3
|
type MaybeEmptyTypes = string | undefined | Array<unknown> | number | Set<unknown> | Map<unknown, unknown> | object;
|
|
4
4
|
type MaybeFunction = (...parameters: unknown[]) => TBlackHole;
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Type guard and basic utility class for runtime type testing.
|
|
7
|
+
*
|
|
8
|
+
* @remarks
|
|
9
|
+
* Provides a unified API for type narrowing, equality, emptiness checks, and
|
|
10
|
+
* basic conversions. All methods are designed as type guards where applicable
|
|
11
|
+
* (e.g., `array()`, `string()` narrow their arguments) and simple predicates
|
|
12
|
+
* elsewhere (e.g., `even()`, `empty()`). The singleton `is` instance is
|
|
13
|
+
* imported directly in lifecycle and wiring services to avoid circular
|
|
14
|
+
* dependencies; everywhere else it is accessed via `internal.utils.is`.
|
|
7
15
|
*/
|
|
8
16
|
export declare class IsIt {
|
|
9
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Test whether a value is an array.
|
|
19
|
+
*/
|
|
20
|
+
array<T>(test: unknown): test is Array<T>;
|
|
21
|
+
/**
|
|
22
|
+
* Test whether a value is a boolean.
|
|
23
|
+
*/
|
|
10
24
|
boolean(test: unknown): test is boolean;
|
|
11
25
|
/**
|
|
12
|
-
*
|
|
26
|
+
* Test whether a value is a valid context (branded string).
|
|
27
|
+
*
|
|
28
|
+
* @remarks
|
|
29
|
+
* The internals of this test may get more creative as context evolves;
|
|
30
|
+
* currently a simple string type guard.
|
|
13
31
|
*/
|
|
14
32
|
context(test: unknown): test is TContext;
|
|
15
33
|
/**
|
|
16
|
-
*
|
|
34
|
+
* Test whether a value is a valid Date object.
|
|
35
|
+
*
|
|
36
|
+
* @remarks
|
|
37
|
+
* Checks both that the value is a Date and that its time is a valid number;
|
|
38
|
+
* this filters out invalid Date instances like `new Date(NaN)`.
|
|
17
39
|
*/
|
|
18
40
|
date(test: unknown): test is Date;
|
|
41
|
+
/**
|
|
42
|
+
* Test whether a value is a valid dayjs instance.
|
|
43
|
+
*/
|
|
19
44
|
dayjs(test: unknown): test is Dayjs;
|
|
45
|
+
/**
|
|
46
|
+
* Test whether a value is empty: undefined, zero-length, zero size, or empty object.
|
|
47
|
+
*
|
|
48
|
+
* @throws When the input type is not recognized (string, array, Map, Set, object, number, undefined).
|
|
49
|
+
*/
|
|
20
50
|
empty(test: MaybeEmptyTypes): boolean;
|
|
21
51
|
/**
|
|
22
52
|
* #MARK: Deep equality test
|
|
23
53
|
*/
|
|
54
|
+
/**
|
|
55
|
+
* Test whether two values are deeply equal using strict comparison.
|
|
56
|
+
*/
|
|
24
57
|
equal<T extends unknown>(a: T, b: T): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Test whether a number is even.
|
|
60
|
+
*/
|
|
25
61
|
even(test: number): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Test whether a value is a function.
|
|
64
|
+
*/
|
|
26
65
|
function<T extends MaybeFunction>(test: unknown): test is T;
|
|
66
|
+
/**
|
|
67
|
+
* Test whether a value is a valid number (not NaN).
|
|
68
|
+
*/
|
|
27
69
|
number(test: unknown): test is number;
|
|
70
|
+
/**
|
|
71
|
+
* Test whether a value is a plain object (not an array or null).
|
|
72
|
+
*/
|
|
28
73
|
object(test: unknown): test is object;
|
|
74
|
+
/**
|
|
75
|
+
* Return a random element from the provided list.
|
|
76
|
+
*/
|
|
29
77
|
random<T>(list: T[]): T;
|
|
78
|
+
/**
|
|
79
|
+
* Test whether a value is a string.
|
|
80
|
+
*/
|
|
30
81
|
string(test: unknown): test is string;
|
|
82
|
+
/**
|
|
83
|
+
* Test whether a value is a symbol.
|
|
84
|
+
*/
|
|
31
85
|
symbol(test: unknown): test is symbol;
|
|
86
|
+
/**
|
|
87
|
+
* Test whether a value is undefined.
|
|
88
|
+
*/
|
|
32
89
|
undefined(test: unknown): test is undefined;
|
|
90
|
+
/**
|
|
91
|
+
* Return a new array containing unique items from the input (deduplication).
|
|
92
|
+
*/
|
|
33
93
|
unique<T>(items: T[]): T[];
|
|
34
94
|
}
|
|
35
95
|
export declare const is: IsIt;
|
|
@@ -3,32 +3,63 @@ import { isDeepStrictEqual, types } from "node:util";
|
|
|
3
3
|
import dayjs from "dayjs";
|
|
4
4
|
import { EMPTY, EVEN } from "../index.mjs";
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Type guard and basic utility class for runtime type testing.
|
|
7
|
+
*
|
|
8
|
+
* @remarks
|
|
9
|
+
* Provides a unified API for type narrowing, equality, emptiness checks, and
|
|
10
|
+
* basic conversions. All methods are designed as type guards where applicable
|
|
11
|
+
* (e.g., `array()`, `string()` narrow their arguments) and simple predicates
|
|
12
|
+
* elsewhere (e.g., `even()`, `empty()`). The singleton `is` instance is
|
|
13
|
+
* imported directly in lifecycle and wiring services to avoid circular
|
|
14
|
+
* dependencies; everywhere else it is accessed via `internal.utils.is`.
|
|
7
15
|
*/
|
|
8
16
|
export class IsIt {
|
|
17
|
+
/**
|
|
18
|
+
* Test whether a value is an array.
|
|
19
|
+
*/
|
|
9
20
|
array(test) {
|
|
10
21
|
return Array.isArray(test);
|
|
11
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Test whether a value is a boolean.
|
|
25
|
+
*/
|
|
12
26
|
boolean(test) {
|
|
13
27
|
return typeof test === "boolean";
|
|
14
28
|
}
|
|
15
29
|
/**
|
|
16
|
-
*
|
|
30
|
+
* Test whether a value is a valid context (branded string).
|
|
31
|
+
*
|
|
32
|
+
* @remarks
|
|
33
|
+
* The internals of this test may get more creative as context evolves;
|
|
34
|
+
* currently a simple string type guard.
|
|
17
35
|
*/
|
|
18
36
|
context(test) {
|
|
19
37
|
return typeof test === "string";
|
|
20
38
|
}
|
|
21
39
|
/**
|
|
22
|
-
*
|
|
40
|
+
* Test whether a value is a valid Date object.
|
|
41
|
+
*
|
|
42
|
+
* @remarks
|
|
43
|
+
* Checks both that the value is a Date and that its time is a valid number;
|
|
44
|
+
* this filters out invalid Date instances like `new Date(NaN)`.
|
|
23
45
|
*/
|
|
24
46
|
date(test) {
|
|
25
47
|
return types.isDate(test) && is.number(test.getTime());
|
|
26
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Test whether a value is a valid dayjs instance.
|
|
51
|
+
*/
|
|
27
52
|
dayjs(test) {
|
|
28
53
|
return test instanceof dayjs && test.isValid();
|
|
29
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Test whether a value is empty: undefined, zero-length, zero size, or empty object.
|
|
57
|
+
*
|
|
58
|
+
* @throws When the input type is not recognized (string, array, Map, Set, object, number, undefined).
|
|
59
|
+
*/
|
|
30
60
|
empty(test) {
|
|
31
61
|
if (test === undefined) {
|
|
62
|
+
// undefined is always empty
|
|
32
63
|
return true;
|
|
33
64
|
}
|
|
34
65
|
if (typeof test === "string" || Array.isArray(test)) {
|
|
@@ -38,6 +69,7 @@ export class IsIt {
|
|
|
38
69
|
return test.size === EMPTY;
|
|
39
70
|
}
|
|
40
71
|
if (typeof test === "object") {
|
|
72
|
+
// walk the object to detect whether any own properties exist
|
|
41
73
|
for (const key in test) {
|
|
42
74
|
if (Object.prototype.hasOwnProperty.call(test, key)) {
|
|
43
75
|
return false;
|
|
@@ -46,42 +78,73 @@ export class IsIt {
|
|
|
46
78
|
return true;
|
|
47
79
|
}
|
|
48
80
|
if (typeof test === "number") {
|
|
81
|
+
// NaN is the only number that is empty
|
|
49
82
|
return Number.isNaN(test);
|
|
50
83
|
}
|
|
51
|
-
//
|
|
84
|
+
// unsupported type — reject rather than silently pass
|
|
52
85
|
throw new Error("Unsupported type " + typeof test);
|
|
53
86
|
}
|
|
54
87
|
/**
|
|
55
88
|
* #MARK: Deep equality test
|
|
56
89
|
*/
|
|
90
|
+
/**
|
|
91
|
+
* Test whether two values are deeply equal using strict comparison.
|
|
92
|
+
*/
|
|
57
93
|
equal(a, b) {
|
|
58
94
|
return isDeepStrictEqual(a, b);
|
|
59
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Test whether a number is even.
|
|
98
|
+
*/
|
|
60
99
|
even(test) {
|
|
61
100
|
return test % EVEN === EMPTY;
|
|
62
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Test whether a value is a function.
|
|
104
|
+
*/
|
|
63
105
|
function(test) {
|
|
64
106
|
return typeof test === "function";
|
|
65
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Test whether a value is a valid number (not NaN).
|
|
110
|
+
*/
|
|
66
111
|
number(test) {
|
|
67
112
|
return typeof test === "number" && !Number.isNaN(test);
|
|
68
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* Test whether a value is a plain object (not an array or null).
|
|
116
|
+
*/
|
|
69
117
|
object(test) {
|
|
70
118
|
return typeof test === "object" && test !== null && !Array.isArray(test);
|
|
71
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Return a random element from the provided list.
|
|
122
|
+
*/
|
|
72
123
|
random(list) {
|
|
73
124
|
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
|
|
74
125
|
return list[Math.floor(randomBytes(1)[0] % list.length)];
|
|
75
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* Test whether a value is a string.
|
|
129
|
+
*/
|
|
76
130
|
string(test) {
|
|
77
131
|
return typeof test === "string";
|
|
78
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* Test whether a value is a symbol.
|
|
135
|
+
*/
|
|
79
136
|
symbol(test) {
|
|
80
137
|
return typeof test === "symbol";
|
|
81
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
* Test whether a value is undefined.
|
|
141
|
+
*/
|
|
82
142
|
undefined(test) {
|
|
83
143
|
return test === undefined;
|
|
84
144
|
}
|
|
145
|
+
/**
|
|
146
|
+
* Return a new array containing unique items from the input (deduplication).
|
|
147
|
+
*/
|
|
85
148
|
unique(items) {
|
|
86
149
|
return [...new Set(items)];
|
|
87
150
|
}
|