@travetto/runtime 5.0.0-rc.2
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 +21 -0
- package/README.md +304 -0
- package/__index__.ts +16 -0
- package/package.json +48 -0
- package/src/console.ts +137 -0
- package/src/context.ts +100 -0
- package/src/env.ts +109 -0
- package/src/error.ts +66 -0
- package/src/exec.ts +156 -0
- package/src/file-loader.ts +59 -0
- package/src/function.ts +42 -0
- package/src/global.d.ts +3 -0
- package/src/manifest-index.ts +4 -0
- package/src/resources.ts +26 -0
- package/src/shutdown.ts +65 -0
- package/src/time.ts +101 -0
- package/src/trv.d.ts +59 -0
- package/src/types.ts +12 -0
- package/src/util.ts +104 -0
- package/src/watch.ts +38 -0
- package/support/transformer.console-log.ts +113 -0
- package/support/transformer.function-metadata.ts +137 -0
- package/support/transformer.rewrite-path-import.ts +39 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 ArcSine 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.
|
package/README.md
ADDED
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
<!-- This file was generated by @travetto/doc and should not be modified directly -->
|
|
2
|
+
<!-- Please modify https://github.com/travetto/travetto/tree/main/module/runtime/DOC.tsx and execute "npx trv doc" to rebuild -->
|
|
3
|
+
# Runtime
|
|
4
|
+
|
|
5
|
+
## Runtime for travetto applications.
|
|
6
|
+
|
|
7
|
+
**Install: @travetto/runtime**
|
|
8
|
+
```bash
|
|
9
|
+
npm install @travetto/runtime
|
|
10
|
+
|
|
11
|
+
# or
|
|
12
|
+
|
|
13
|
+
yarn add @travetto/runtime
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Runtime is the foundation of all [Travetto](https://travetto.dev) applications. It is intended to be a minimal application set, as well as support for commonly shared functionality. It has support for the following key areas:
|
|
17
|
+
* Environment Support
|
|
18
|
+
* Runtime Context
|
|
19
|
+
* Console Management
|
|
20
|
+
* Resource Access
|
|
21
|
+
* Standard Error Support
|
|
22
|
+
* Common Utilities
|
|
23
|
+
* Time Utilities
|
|
24
|
+
* Process Execution
|
|
25
|
+
* Shutdown Management
|
|
26
|
+
* Path behavior
|
|
27
|
+
|
|
28
|
+
## Environment Support
|
|
29
|
+
The functionality we support for testing and retrieving environment information for known environment variables. They can be accessed directly on the [Env](https://github.com/travetto/travetto/tree/main/module/runtime/src/env.ts#L109) object, and will return a scoped [EnvProp](https://github.com/travetto/travetto/tree/main/module/runtime/src/env.ts#L4), that is compatible with the property definition. E.g. only showing boolean related fields when the underlying flag supports `true` or `false`
|
|
30
|
+
|
|
31
|
+
**Code: Base Known Environment Flags**
|
|
32
|
+
```typescript
|
|
33
|
+
interface TravettoEnv {
|
|
34
|
+
/**
|
|
35
|
+
* The node environment we are running in
|
|
36
|
+
* @default development
|
|
37
|
+
*/
|
|
38
|
+
NODE_ENV: 'development' | 'production';
|
|
39
|
+
/**
|
|
40
|
+
* Outputs all console.debug messages, defaults to `local` in dev, and `off` in prod.
|
|
41
|
+
*/
|
|
42
|
+
DEBUG: boolean | string;
|
|
43
|
+
/**
|
|
44
|
+
* Environment to deploy, defaults to `NODE_ENV` if not `TRV_ENV` is not specified.
|
|
45
|
+
*/
|
|
46
|
+
TRV_ENV: string;
|
|
47
|
+
/**
|
|
48
|
+
* Special role to run as, used to access additional files from the manifest during runtime.
|
|
49
|
+
*/
|
|
50
|
+
TRV_ROLE: Role;
|
|
51
|
+
/**
|
|
52
|
+
* Whether or not to run the program in dynamic mode, allowing for real-time updates
|
|
53
|
+
*/
|
|
54
|
+
TRV_DYNAMIC: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* The folders to use for resource lookup
|
|
57
|
+
*/
|
|
58
|
+
TRV_RESOURCES: string[];
|
|
59
|
+
/**
|
|
60
|
+
* Resource path overrides
|
|
61
|
+
* @private
|
|
62
|
+
*/
|
|
63
|
+
TRV_RESOURCE_OVERRIDES: Record<string, string>;
|
|
64
|
+
/**
|
|
65
|
+
* The max time to wait for shutdown to finish after initial SIGINT,
|
|
66
|
+
* @default 2s
|
|
67
|
+
*/
|
|
68
|
+
TRV_SHUTDOWN_WAIT: TimeSpan | number;
|
|
69
|
+
/**
|
|
70
|
+
* The desired runtime module
|
|
71
|
+
*/
|
|
72
|
+
TRV_MODULE: string;
|
|
73
|
+
/**
|
|
74
|
+
* The location of the manifest file
|
|
75
|
+
* @default undefined
|
|
76
|
+
*/
|
|
77
|
+
TRV_MANIFEST: string;
|
|
78
|
+
/**
|
|
79
|
+
* trvc log level
|
|
80
|
+
*/
|
|
81
|
+
TRV_BUILD: 'none' | 'info' | 'debug' | 'error' | 'warn'
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Environment Property
|
|
86
|
+
For a given [EnvProp](https://github.com/travetto/travetto/tree/main/module/runtime/src/env.ts#L4), we support the ability to access different properties as a means to better facilitate environment variable usage.
|
|
87
|
+
|
|
88
|
+
**Code: EnvProp Shape**
|
|
89
|
+
```typescript
|
|
90
|
+
export class EnvProp<T> {
|
|
91
|
+
constructor(public readonly key: string) { }
|
|
92
|
+
/** Remove value */
|
|
93
|
+
clear(): void;
|
|
94
|
+
/** Export value */
|
|
95
|
+
export(val: T | undefined): Record<string, string>;
|
|
96
|
+
/** Read value as string */
|
|
97
|
+
get val(): string | undefined;
|
|
98
|
+
/** Read value as list */
|
|
99
|
+
get list(): string[] | undefined;
|
|
100
|
+
/** Read value as object */
|
|
101
|
+
get object(): Record<string, string> | undefined;
|
|
102
|
+
/** Add values to list */
|
|
103
|
+
add(...items: string[]): void;
|
|
104
|
+
/** Read value as int */
|
|
105
|
+
get int(): number | undefined;
|
|
106
|
+
/** Read value as boolean */
|
|
107
|
+
get bool(): boolean | undefined;
|
|
108
|
+
/** Determine if the underlying value is truthy */
|
|
109
|
+
get isTrue(): boolean;
|
|
110
|
+
/** Determine if the underlying value is falsy */
|
|
111
|
+
get isFalse(): boolean;
|
|
112
|
+
/** Determine if the underlying value is set */
|
|
113
|
+
get isSet(): boolean;
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Resource Access
|
|
118
|
+
The primary access patterns for resources, is to directly request a file, and to resolve that file either via file-system look up or leveraging the [Manifest](https://github.com/travetto/travetto/tree/main/module/manifest#readme "Support for project indexing, manifesting, along with file watching")'s data for what resources were found at manifesting time.
|
|
119
|
+
|
|
120
|
+
The [FileLoader](https://github.com/travetto/travetto/tree/main/module/runtime/src/file-loader.ts#L11) allows for accessing information about the resources, and subsequently reading the file as text/binary or to access the resource as a `Readable` stream. If a file is not found, it will throw an [AppError](https://github.com/travetto/travetto/tree/main/module/runtime/src/error.ts#L13) with a category of 'notfound'.
|
|
121
|
+
|
|
122
|
+
The [FileLoader](https://github.com/travetto/travetto/tree/main/module/runtime/src/file-loader.ts#L11) also supports tying itself to [Env](https://github.com/travetto/travetto/tree/main/module/runtime/src/env.ts#L109)'s `TRV_RESOURCES` information on where to attempt to find a requested resource.
|
|
123
|
+
|
|
124
|
+
## Standard Error Support
|
|
125
|
+
While the framework is 100 % compatible with standard `Error` instances, there are cases in which additional functionality is desired. Within the framework we use [AppError](https://github.com/travetto/travetto/tree/main/module/runtime/src/error.ts#L13) (or its derivatives) to represent framework errors. This class is available for use in your own projects. Some of the additional benefits of using this class is enhanced error reporting, as well as better integration with other modules (e.g. the [RESTful API](https://github.com/travetto/travetto/tree/main/module/rest#readme "Declarative api for RESTful APIs with support for the dependency injection module.") module and HTTP status codes).
|
|
126
|
+
|
|
127
|
+
The [AppError](https://github.com/travetto/travetto/tree/main/module/runtime/src/error.ts#L13) takes in a message, and an optional payload and / or error classification. The currently supported error classifications are:
|
|
128
|
+
* `general` - General purpose errors
|
|
129
|
+
* `system` - Synonym for `general`
|
|
130
|
+
* `data` - Data format, content, etc are incorrect. Generally correlated to bad input.
|
|
131
|
+
* `permission` - Operation failed due to lack of permissions
|
|
132
|
+
* `auth` - Operation failed due to lack of authentication
|
|
133
|
+
* `missing` - Resource was not found when requested
|
|
134
|
+
* `timeout` - Operation did not finish in a timely manner
|
|
135
|
+
* `unavailable` - Resource was unresponsive
|
|
136
|
+
|
|
137
|
+
## Console Management
|
|
138
|
+
This module provides logging functionality, built upon [console](https://nodejs.org/api/console.html) operations.
|
|
139
|
+
|
|
140
|
+
The supported operations are:
|
|
141
|
+
* `console.error` which logs at the `ERROR` level
|
|
142
|
+
* `console.warn` which logs at the `WARN` level
|
|
143
|
+
* `console.info` which logs at the `INFO` level
|
|
144
|
+
* `console.debug` which logs at the `DEBUG` level
|
|
145
|
+
* `console.log` which logs at the `INFO` level
|
|
146
|
+
|
|
147
|
+
**Note**: All other console methods are excluded, specifically `trace`, `inspect`, `dir`, `time`/`timeEnd`
|
|
148
|
+
|
|
149
|
+
## How Logging is Instrumented
|
|
150
|
+
All of the logging instrumentation occurs at transpilation time. All `console.*` methods are replaced with a call to a globally defined variable that delegates to the [ConsoleManager](https://github.com/travetto/travetto/tree/main/module/runtime/src/console.ts#L35). This module, hooks into the [ConsoleManager](https://github.com/travetto/travetto/tree/main/module/runtime/src/console.ts#L35) and receives all logging events from all files compiled by the [Travetto](https://travetto.dev).
|
|
151
|
+
|
|
152
|
+
A sample of the instrumentation would be:
|
|
153
|
+
|
|
154
|
+
**Code: Sample logging at various levels**
|
|
155
|
+
```typescript
|
|
156
|
+
export function work() {
|
|
157
|
+
console.debug('Start Work');
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
1 / 0;
|
|
161
|
+
} catch (err) {
|
|
162
|
+
console.error('Divide by zero', { error: err });
|
|
163
|
+
}
|
|
164
|
+
console.debug('End Work');
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Code: Sample After Transpilation**
|
|
169
|
+
```javascript
|
|
170
|
+
"use strict";
|
|
171
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
172
|
+
exports.work = work;
|
|
173
|
+
const tslib_1 = require("tslib");
|
|
174
|
+
const ᚕ_c = tslib_1.__importStar(require("@travetto/runtime/src/console.js"));
|
|
175
|
+
var ᚕm = ["@travetto/runtime", "doc/transpile"];
|
|
176
|
+
function work() {
|
|
177
|
+
ᚕ_c.log({ level: "debug", import: ᚕm, line: 2, scope: "work", args: ['Start Work'] });
|
|
178
|
+
try {
|
|
179
|
+
1 / 0;
|
|
180
|
+
}
|
|
181
|
+
catch (err) {
|
|
182
|
+
ᚕ_c.log({ level: "error", import: ᚕm, line: 7, scope: "work", args: ['Divide by zero', { error: err }] });
|
|
183
|
+
}
|
|
184
|
+
ᚕ_c.log({ level: "debug", import: ᚕm, line: 9, scope: "work", args: ['End Work'] });
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Filtering Debug
|
|
189
|
+
The `debug` messages can be filtered using the patterns from the [debug](https://www.npmjs.com/package/debug). You can specify wild cards to only `DEBUG` specific modules, folders or files. You can specify multiple, and you can also add negations to exclude specific packages.
|
|
190
|
+
|
|
191
|
+
**Terminal: Sample environment flags**
|
|
192
|
+
```bash
|
|
193
|
+
|
|
194
|
+
# Debug
|
|
195
|
+
$ DEBUG=-@travetto/model npx trv run app
|
|
196
|
+
$ DEBUG=-@travetto/registry npx trv run app
|
|
197
|
+
$ DEBUG=@travetto/rest npx trv run app
|
|
198
|
+
$ DEBUG=@travetto/*,-@travetto/model npx trv run app
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Additionally, the logging framework will merge [debug](https://www.npmjs.com/package/debug) into the output stream, and supports the standard usage
|
|
202
|
+
|
|
203
|
+
**Terminal: Sample environment flags for standard usage**
|
|
204
|
+
```bash
|
|
205
|
+
|
|
206
|
+
# Debug
|
|
207
|
+
$ DEBUG=express:*,@travetto/rest npx trv run rest
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Common Utilities
|
|
211
|
+
Common utilities used throughout the framework. Currently [Util](https://github.com/travetto/travetto/tree/main/module/runtime/src/util.ts#L17) includes:
|
|
212
|
+
* `uuid(len: number)` generates a simple uuid for use within the application.
|
|
213
|
+
* `allowDenyMatcher(rules[])` builds a matching function that leverages the rules as an allow/deny list, where order of the rules matters. Negative rules are prefixed by '!'.
|
|
214
|
+
* `hash(text: string, size?: number)` produces a full sha512 hash.
|
|
215
|
+
* `resolvablePromise()` produces a `Promise` instance with the `resolve` and `reject` methods attached to the instance. This is extremely useful for integrating promises into async iterations, or any other situation in which the promise creation and the execution flow don't always match up.
|
|
216
|
+
|
|
217
|
+
**Code: Sample makeTemplate Usage**
|
|
218
|
+
```typescript
|
|
219
|
+
const tpl = makeTemplate((name: 'age'|'name', val) => `**${name}: ${val}**`);
|
|
220
|
+
tpl`{{age:20}} {{name: 'bob'}}</>;
|
|
221
|
+
// produces
|
|
222
|
+
'**age: 20** **name: bob**'
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## Time Utilities
|
|
226
|
+
[TimeUtil](https://github.com/travetto/travetto/tree/main/module/runtime/src/time.ts#L17) contains general helper methods, created to assist with time-based inputs via environment variables, command line interfaces, and other string-heavy based input.
|
|
227
|
+
|
|
228
|
+
**Code: Time Utilities**
|
|
229
|
+
```typescript
|
|
230
|
+
export class TimeUtil {
|
|
231
|
+
/**
|
|
232
|
+
* Test to see if a string is valid for relative time
|
|
233
|
+
* @param val
|
|
234
|
+
*/
|
|
235
|
+
static isTimeSpan(val: string): val is TimeSpan;
|
|
236
|
+
/**
|
|
237
|
+
* Returns time units convert to ms
|
|
238
|
+
* @param amount Number of units to extend
|
|
239
|
+
* @param unit Time unit to extend ('ms', 's', 'm', 'h', 'd', 'w', 'y')
|
|
240
|
+
*/
|
|
241
|
+
static asMillis(amount: Date | number | TimeSpan, unit?: TimeUnit): number;
|
|
242
|
+
/**
|
|
243
|
+
* Returns the time converted to seconds
|
|
244
|
+
* @param date The date to convert
|
|
245
|
+
*/
|
|
246
|
+
static asSeconds(date: Date | number | TimeSpan, unit?: TimeUnit): number;
|
|
247
|
+
/**
|
|
248
|
+
* Returns the time converted to a Date
|
|
249
|
+
* @param date The date to convert
|
|
250
|
+
*/
|
|
251
|
+
static asDate(date: Date | number | TimeSpan, unit?: TimeUnit): Date;
|
|
252
|
+
/**
|
|
253
|
+
* Resolve time or span to possible time
|
|
254
|
+
*/
|
|
255
|
+
static fromValue(value: Date | number | string | undefined): number | undefined;
|
|
256
|
+
/**
|
|
257
|
+
* Returns a new date with `amount` units into the future
|
|
258
|
+
* @param amount Number of units to extend
|
|
259
|
+
* @param unit Time unit to extend ('ms', 's', 'm', 'h', 'd', 'w', 'y')
|
|
260
|
+
*/
|
|
261
|
+
static fromNow(amount: number | TimeSpan, unit: TimeUnit = 'ms'): Date;
|
|
262
|
+
/**
|
|
263
|
+
* Returns a pretty timestamp
|
|
264
|
+
* @param time Time in milliseconds
|
|
265
|
+
*/
|
|
266
|
+
static asClock(time: number): string;
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## Process Execution
|
|
271
|
+
[ExecUtil](https://github.com/travetto/travetto/tree/main/module/runtime/src/exec.ts#L39) exposes `getResult` as a means to wrap [child_process](https://nodejs.org/api/child_process.html)'s process object. This wrapper allows for a promise-based resolution of the subprocess with the ability to capture the stderr/stdout.
|
|
272
|
+
|
|
273
|
+
A simple example would be:
|
|
274
|
+
|
|
275
|
+
**Code: Running a directory listing via ls**
|
|
276
|
+
```typescript
|
|
277
|
+
import { spawn } from 'node:child_process';
|
|
278
|
+
import { ExecUtil } from '@travetto/runtime';
|
|
279
|
+
|
|
280
|
+
export async function executeListing() {
|
|
281
|
+
const final = await ExecUtil.getResult(spawn('ls'));
|
|
282
|
+
console.log('Listing', { lines: final.stdout.split('\n') });
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Shutdown Management
|
|
287
|
+
Another key lifecycle is the process of shutting down. The framework provides centralized functionality for running operations on graceful shutdown. Primarily used by the framework for cleanup operations, this provides a clean interface for registering shutdown handlers. The code intercepts `SIGTERM` and `SIGUSR2`, with a default threshold of 2 seconds. These events will start the shutdown process, but also clear out the pending queue. If a kill signal is sent again, it will complete immediately.
|
|
288
|
+
|
|
289
|
+
As a registered shutdown handler, you can do.
|
|
290
|
+
|
|
291
|
+
**Code: Registering a shutdown handler**
|
|
292
|
+
```typescript
|
|
293
|
+
import { ShutdownManager } from '@travetto/runtime';
|
|
294
|
+
|
|
295
|
+
export function registerShutdownHandler() {
|
|
296
|
+
ShutdownManager.onGracefulShutdown(async () => {
|
|
297
|
+
// Do important work, the framework will wait until all async
|
|
298
|
+
// operations are completed before finishing shutdown
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
## Path Behavior
|
|
304
|
+
To ensure consistency in path usage throughout the framework, imports pointing at $`node:path` and $`path` are rewritten at compile time. These imports are pointing towards [Manifest](https://github.com/travetto/travetto/tree/main/module/manifest#readme "Support for project indexing, manifesting, along with file watching")'s `path` implementation. This allows for seamless import/usage patterns with the reliability needed for cross platform support.
|
package/__index__.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/// <reference path="./src/trv.d.ts" />
|
|
2
|
+
/// <reference path="./src/global.d.ts" />
|
|
3
|
+
export * from './src/console';
|
|
4
|
+
export * from './src/context';
|
|
5
|
+
export * from './src/error';
|
|
6
|
+
export * from './src/exec';
|
|
7
|
+
export * from './src/env';
|
|
8
|
+
export * from './src/file-loader';
|
|
9
|
+
export * from './src/function';
|
|
10
|
+
export * from './src/manifest-index';
|
|
11
|
+
export * from './src/resources';
|
|
12
|
+
export * from './src/shutdown';
|
|
13
|
+
export * from './src/time';
|
|
14
|
+
export * from './src/types';
|
|
15
|
+
export * from './src/watch';
|
|
16
|
+
export * from './src/util';
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@travetto/runtime",
|
|
3
|
+
"version": "5.0.0-rc.2",
|
|
4
|
+
"description": "Runtime for travetto applications.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"console-manager",
|
|
7
|
+
"runtime",
|
|
8
|
+
"travetto",
|
|
9
|
+
"typescript"
|
|
10
|
+
],
|
|
11
|
+
"homepage": "https://travetto.io",
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"author": {
|
|
14
|
+
"email": "travetto.framework@gmail.com",
|
|
15
|
+
"name": "Travetto Framework"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"__index__.ts",
|
|
19
|
+
"src",
|
|
20
|
+
"support"
|
|
21
|
+
],
|
|
22
|
+
"main": "__index__.ts",
|
|
23
|
+
"repository": {
|
|
24
|
+
"url": "https://github.com/travetto/travetto.git",
|
|
25
|
+
"directory": "module/runtime"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@travetto/manifest": "^5.0.0-rc.2",
|
|
29
|
+
"@types/debug": "^4.1.12",
|
|
30
|
+
"@types/node": "^20.14.10",
|
|
31
|
+
"debug": "^4.3.5"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"@travetto/transformer": "^5.0.0-rc.2"
|
|
35
|
+
},
|
|
36
|
+
"peerDependenciesMeta": {
|
|
37
|
+
"@travetto/transformer": {
|
|
38
|
+
"optional": true
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"travetto": {
|
|
42
|
+
"displayName": "Runtime"
|
|
43
|
+
},
|
|
44
|
+
"private": false,
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public"
|
|
47
|
+
}
|
|
48
|
+
}
|
package/src/console.ts
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import util from 'node:util';
|
|
2
|
+
import debug from 'debug';
|
|
3
|
+
|
|
4
|
+
import { RuntimeIndex } from './manifest-index';
|
|
5
|
+
|
|
6
|
+
export type ConsoleEvent = {
|
|
7
|
+
/** Time of event */
|
|
8
|
+
timestamp: Date;
|
|
9
|
+
/** The level of the console event */
|
|
10
|
+
level: 'info' | 'warn' | 'debug' | 'error';
|
|
11
|
+
/** The line number the console event was triggered from */
|
|
12
|
+
line: number;
|
|
13
|
+
/** The module name for the source file */
|
|
14
|
+
module: string;
|
|
15
|
+
/** The module path for the source file*/
|
|
16
|
+
modulePath: string;
|
|
17
|
+
/** The computed scope for the console. statement. */
|
|
18
|
+
scope?: string;
|
|
19
|
+
/** Arguments passed to the console call*/
|
|
20
|
+
args: unknown[];
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export interface ConsoleListener {
|
|
24
|
+
log(ev: ConsoleEvent): void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const DEBUG_OG = { formatArgs: debug.formatArgs, log: debug.log };
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Provides a general abstraction against the console.* methods to allow for easier capture and redirection.
|
|
31
|
+
*
|
|
32
|
+
* The transpiler will replace all console.* calls in the typescript files for the framework and those provided by the user.
|
|
33
|
+
* Any console.log statements elsewhere will not be affected.
|
|
34
|
+
*/
|
|
35
|
+
class $ConsoleManager implements ConsoleListener {
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The current listener
|
|
39
|
+
*/
|
|
40
|
+
#listener: ConsoleListener;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* List of logging filters
|
|
44
|
+
*/
|
|
45
|
+
#filters: Partial<Record<ConsoleEvent['level'], (x: ConsoleEvent) => boolean>> = {};
|
|
46
|
+
|
|
47
|
+
constructor(listener: ConsoleListener) {
|
|
48
|
+
this.set(listener);
|
|
49
|
+
this.enhanceDebug(true);
|
|
50
|
+
this.debug(false);
|
|
51
|
+
util.inspect.defaultOptions.depth = Math.max(util.inspect.defaultOptions.depth ?? 0, 4);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Add exclusion
|
|
56
|
+
* @private
|
|
57
|
+
*/
|
|
58
|
+
filter(level: ConsoleEvent['level'], filter?: boolean | ((ctx: ConsoleEvent) => boolean)): void {
|
|
59
|
+
if (filter !== undefined) {
|
|
60
|
+
if (typeof filter === 'boolean') {
|
|
61
|
+
const v = filter;
|
|
62
|
+
filter = (): boolean => v;
|
|
63
|
+
}
|
|
64
|
+
this.#filters[level] = filter;
|
|
65
|
+
} else {
|
|
66
|
+
delete this.#filters[level];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Enable/disable enhanced debugging
|
|
72
|
+
*/
|
|
73
|
+
enhanceDebug(active: boolean): void {
|
|
74
|
+
Error.stackTraceLimit = active ? 50 : 10;
|
|
75
|
+
if (active) {
|
|
76
|
+
debug.formatArgs = function (args: string[]): void {
|
|
77
|
+
args.unshift(this.namespace);
|
|
78
|
+
args.push(debug.humanize(this.diff));
|
|
79
|
+
};
|
|
80
|
+
debug.log = (modulePath, ...args: string[]): void => this.log({
|
|
81
|
+
level: 'debug', module: '@npm:debug', modulePath,
|
|
82
|
+
args: [util.format(...args)], line: 0, timestamp: new Date()
|
|
83
|
+
});
|
|
84
|
+
} else {
|
|
85
|
+
debug.formatArgs = DEBUG_OG.formatArgs;
|
|
86
|
+
debug.log = DEBUG_OG.log;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Set logging debug level
|
|
92
|
+
*/
|
|
93
|
+
debug(value: false | string): void {
|
|
94
|
+
if (value !== false) {
|
|
95
|
+
const active = RuntimeIndex.getModuleList('workspace', value);
|
|
96
|
+
active.add('@npm:debug');
|
|
97
|
+
this.filter('debug', ctx => active.has(ctx.module));
|
|
98
|
+
} else {
|
|
99
|
+
this.filter('debug', () => false);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Handle direct call in lieu of the console.* commands
|
|
105
|
+
*/
|
|
106
|
+
log(ev: ConsoleEvent & { import?: [string, string] }): void {
|
|
107
|
+
const outEv = {
|
|
108
|
+
...ev,
|
|
109
|
+
timestamp: new Date(),
|
|
110
|
+
module: ev.module ?? ev.import?.[0],
|
|
111
|
+
modulePath: ev.modulePath ?? ev.import?.[1]
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
if (this.#filters[outEv.level] && !this.#filters[outEv.level]!(outEv)) {
|
|
115
|
+
return; // Do nothing
|
|
116
|
+
} else {
|
|
117
|
+
return this.#listener.log(outEv);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Set a new console listener
|
|
123
|
+
*/
|
|
124
|
+
set(cons: ConsoleListener): void {
|
|
125
|
+
this.#listener = cons;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Get the listener
|
|
130
|
+
*/
|
|
131
|
+
get(): ConsoleListener {
|
|
132
|
+
return this.#listener;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export const ConsoleManager = new $ConsoleManager({ log(ev): void { console; } });
|
|
137
|
+
export const log = ConsoleManager.log.bind(ConsoleManager);
|
package/src/context.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
|
|
3
|
+
import { type ManifestContext } from '@travetto/manifest';
|
|
4
|
+
|
|
5
|
+
import { Env } from './env';
|
|
6
|
+
import { RuntimeIndex } from './manifest-index';
|
|
7
|
+
import { describeFunction } from './function';
|
|
8
|
+
|
|
9
|
+
const prod = (): boolean => process.env.NODE_ENV === 'production';
|
|
10
|
+
|
|
11
|
+
const OVERRIDES = Env.TRV_RESOURCE_OVERRIDES.object ?? {};
|
|
12
|
+
|
|
13
|
+
const MODULE_ALIASES: Record<string, string> = {
|
|
14
|
+
'@': RuntimeIndex.manifest.main.name,
|
|
15
|
+
'@@': RuntimeIndex.manifest.workspace.path,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
/** Constrained version of {@type ManifestContext} */
|
|
20
|
+
export const Runtime = {
|
|
21
|
+
/** Get env name, with support for the default env */
|
|
22
|
+
get name(): string | undefined {
|
|
23
|
+
return Env.TRV_ENV.val || (!prod() ? RuntimeIndex.manifest.workspace.defaultEnv : undefined);
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
/** Are we in development mode */
|
|
27
|
+
get production(): boolean {
|
|
28
|
+
return prod();
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
/** Is the app in dynamic mode? */
|
|
32
|
+
get dynamic(): boolean {
|
|
33
|
+
return Env.TRV_DYNAMIC.isTrue;
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
/** Get debug value */
|
|
37
|
+
get debug(): false | string {
|
|
38
|
+
const val = Env.DEBUG.val ?? '';
|
|
39
|
+
return (!val && prod()) || Env.DEBUG.isFalse ? false : val;
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
/** Manifest main */
|
|
43
|
+
get main(): ManifestContext['main'] {
|
|
44
|
+
return RuntimeIndex.manifest.main;
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
/** Manifest workspace */
|
|
48
|
+
get workspace(): ManifestContext['workspace'] {
|
|
49
|
+
return RuntimeIndex.manifest.workspace;
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
/** Are we running from a mono-root? */
|
|
53
|
+
get monoRoot(): boolean {
|
|
54
|
+
return !!RuntimeIndex.manifest.workspace.mono && !RuntimeIndex.manifest.main.folder;
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
/** Main source path */
|
|
58
|
+
get mainSourcePath(): string {
|
|
59
|
+
return RuntimeIndex.mainModule.sourcePath;
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
/** Produce a workspace relative path */
|
|
63
|
+
workspaceRelative(...rel: string[]): string {
|
|
64
|
+
return path.resolve(RuntimeIndex.manifest.workspace.path, ...rel);
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
/** Strip off the workspace path from a file */
|
|
68
|
+
stripWorkspacePath(full: string): string {
|
|
69
|
+
return full === RuntimeIndex.manifest.workspace.path ? '' : full.replace(`${RuntimeIndex.manifest.workspace.path}/`, '');
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
/** Produce a workspace path for tooling, with '@' being replaced by node_module/name folder */
|
|
73
|
+
toolPath(...rel: string[]): string {
|
|
74
|
+
rel = rel.flatMap(x => x === '@' ? ['node_modules', RuntimeIndex.manifest.main.name] : [x]);
|
|
75
|
+
return path.resolve(RuntimeIndex.manifest.workspace.path, RuntimeIndex.manifest.build.toolFolder, ...rel);
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
/** Resolve single module path */
|
|
79
|
+
modulePath(modulePath: string): string {
|
|
80
|
+
const [base, sub] = (OVERRIDES[modulePath] ?? modulePath)
|
|
81
|
+
.replace(/^([^#]*)(#|$)/g, (_, v, r) => `${MODULE_ALIASES[v] ?? v}${r}`)
|
|
82
|
+
.split('#');
|
|
83
|
+
return path.resolve(RuntimeIndex.getModule(base)?.sourcePath ?? base, sub ?? '.');
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
/** Resolve module paths */
|
|
87
|
+
modulePaths(paths: string[]): string[] {
|
|
88
|
+
return [...new Set(paths.map(this.modulePath))];
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
/** Resolve resource paths */
|
|
92
|
+
resourcePaths(paths: string[] = []): string[] {
|
|
93
|
+
return this.modulePaths([...paths, ...Env.TRV_RESOURCES.list ?? [], '@#resources', '@@#resources']);
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
/** Get source for function */
|
|
97
|
+
getSource(fn: Function): string {
|
|
98
|
+
return RuntimeIndex.getFromImport(describeFunction(fn).import)?.sourceFile!;
|
|
99
|
+
}
|
|
100
|
+
};
|