@travetto/runtime 5.0.10 → 5.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -164,9 +164,9 @@ export class EnvProp<T> {
164
164
  ```
165
165
 
166
166
  ## Standard Error Support
167
- 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#L15) (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).
167
+ 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#L26) (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).
168
168
 
169
- The [AppError](https://github.com/travetto/travetto/tree/main/module/runtime/src/error.ts#L15) takes in a message, and an optional payload and / or error classification. The currently supported error classifications are:
169
+ The [AppError](https://github.com/travetto/travetto/tree/main/module/runtime/src/error.ts#L26) takes in a message, and an optional payload and / or error classification. The currently supported error classifications are:
170
170
  * `general` - General purpose errors
171
171
  * `system` - Synonym for `general`
172
172
  * `data` - Data format, content, etc are incorrect. Generally correlated to bad input.
@@ -254,7 +254,7 @@ $ DEBUG=express:*,@travetto/rest npx trv run rest
254
254
  ## Resource Access
255
255
  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.
256
256
 
257
- 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#L15) with a category of 'notfound'.
257
+ 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#L26) with a category of 'notfound'.
258
258
 
259
259
  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#L111)'s `TRV_RESOURCES` information on where to attempt to find a requested resource.
260
260
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/runtime",
3
- "version": "5.0.10",
3
+ "version": "5.0.12",
4
4
  "description": "Runtime for travetto applications.",
5
5
  "keywords": [
6
6
  "console-manager",
@@ -28,13 +28,13 @@
28
28
  "node": ">=22.0.0"
29
29
  },
30
30
  "dependencies": {
31
- "@travetto/manifest": "^5.0.7",
31
+ "@travetto/manifest": "^5.0.9",
32
32
  "@types/debug": "^4.1.12",
33
- "@types/node": "^22.7.4",
33
+ "@types/node": "^22.7.9",
34
34
  "debug": "^4.3.7"
35
35
  },
36
36
  "peerDependencies": {
37
- "@travetto/transformer": "^5.0.8"
37
+ "@travetto/transformer": "^5.0.10"
38
38
  },
39
39
  "peerDependenciesMeta": {
40
40
  "@travetto/transformer": {
package/src/binary.ts CHANGED
@@ -108,7 +108,7 @@ export class BinaryUtil {
108
108
  transform(chunk, encoding, callback): void {
109
109
  read += (Buffer.isBuffer(chunk) || typeof chunk === 'string') ? chunk.length : (chunk instanceof Uint8Array ? chunk.byteLength : 0);
110
110
  if (read > maxSize) {
111
- callback(new AppError('File size exceeded', 'data', { read, size: maxSize }));
111
+ callback(new AppError('File size exceeded', { category: 'data', details: { read, size: maxSize } }));
112
112
  } else {
113
113
  callback(null, chunk);
114
114
  }
package/src/error.ts CHANGED
@@ -9,10 +9,21 @@ export type ErrorCategory =
9
9
  'timeout' |
10
10
  'unavailable';
11
11
 
12
+ export type AppErrorOptions<T> =
13
+ ErrorOptions &
14
+ {
15
+ at?: Date | string | number;
16
+ type?: string;
17
+ category?: ErrorCategory;
18
+ } &
19
+ (T extends undefined ?
20
+ { details?: T } :
21
+ { details: T });
22
+
12
23
  /**
13
24
  * Framework error class, with the aim of being extensible
14
25
  */
15
- export class AppError<T = unknown> extends Error {
26
+ export class AppError<T = Record<string, unknown> | undefined> extends Error {
16
27
 
17
28
  /** Convert from JSON object */
18
29
  static fromJSON(e: unknown): AppError | undefined {
@@ -20,47 +31,46 @@ export class AppError<T = unknown> extends Error {
20
31
  ('message' in e && typeof e.message === 'string') &&
21
32
  ('category' in e && typeof e.category === 'string') &&
22
33
  ('type' in e && typeof e.type === 'string') &&
23
- ('at' in e && typeof e.at === 'number')
34
+ ('at' in e && typeof e.at === 'string')
24
35
  ) {
25
- const err = new AppError(e.message, castTo(e.category), 'details' in e ? e.details : undefined);
26
- err.at = new Date(e.at);
27
- err.type = e.type;
28
- return err;
36
+ return new AppError(e.message, castTo<AppErrorOptions<Record<string, unknown>>>(e));
29
37
  }
30
38
  }
31
39
 
32
40
  type: string;
33
- at = new Date();
41
+ category: ErrorCategory;
42
+ at: string;
34
43
  details: T;
35
44
 
36
45
  /**
37
46
  * Build an app error
38
47
  *
39
48
  * @param message The error message
40
- * @param category The error category, can be mapped to HTTP statuses
41
- * @param details Optional error payload
42
49
  */
43
50
  constructor(
44
- message: string,
45
- public category: ErrorCategory = 'general',
46
- details?: T
47
-
51
+ ...[message, opts]:
52
+ T extends undefined ? ([string] | [string, AppErrorOptions<T>]) : [string, AppErrorOptions<T>]
48
53
  ) {
49
- super(message);
50
- this.type = this.constructor.name;
51
- this.details = details!;
54
+ super(message, opts?.cause ? { cause: opts.cause } : undefined);
55
+ this.type = opts?.type ?? this.constructor.name;
56
+ this.details = opts?.details!;
57
+ this.category = opts?.category ?? 'general';
58
+ this.at = new Date(opts?.at ?? Date.now()).toISOString();
52
59
  }
53
60
 
54
61
  /**
55
- * The format of the JSON output
62
+ * Serializes an error to a basic object
56
63
  */
57
- toJSON(): { message: string, category: string, type: string, at: string, details?: Record<string, unknown> } {
58
- return {
59
- message: this.message,
64
+ toJSON(): AppErrorOptions<T> & { message: string } {
65
+ const res: AppErrorOptions<unknown> = {
60
66
  category: this.category,
67
+ ...(this.cause ? { cause: `${this.cause}` } : undefined),
61
68
  type: this.type,
62
- at: this.at.toISOString(),
63
- details: castTo(this.details),
69
+ at: this.at,
70
+ ...(this.details ? { details: this.details } : undefined!),
64
71
  };
72
+
73
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
74
+ return { message: this.message, ...res as AppErrorOptions<T> };
65
75
  }
66
76
  }
@@ -34,7 +34,7 @@ export class FileLoader {
34
34
  return resolved;
35
35
  }
36
36
  }
37
- throw new AppError(`Unable to find: ${relativePath}, searched=${this.searchPaths.join(',')}`, 'notfound');
37
+ throw new AppError(`Unable to find: ${relativePath}, searched=${this.searchPaths.join(',')}`, { category: 'notfound' });
38
38
  }
39
39
 
40
40
  /**
package/src/types.ts CHANGED
@@ -49,6 +49,8 @@ export function classConstruct<T>(cls: Class<T>, args: unknown[] = []): ClassIns
49
49
  export const hasFunction = <T>(key: keyof T) => (o: unknown): o is T =>
50
50
  typeof o === 'object' && o !== null && typeof o[castKey(key)] === 'function';
51
51
 
52
+ export const hasToJSON = hasFunction<{ toJSON(): object }>('toJSON');
53
+
52
54
  /**
53
55
  * Range of bytes, inclusive
54
56
  */
package/src/util.ts CHANGED
@@ -47,10 +47,12 @@ export class Util {
47
47
  */
48
48
  static uuid(len: number = 32): string {
49
49
  const bytes = crypto.randomBytes(Math.ceil(len / 2));
50
- // eslint-disable-next-line no-bitwise
51
- bytes[6] = (bytes[6] & 0x0f) | 0x40;
52
- // eslint-disable-next-line no-bitwise
53
- bytes[8] = (bytes[8] & 0x3f) | 0x80;
50
+ if (len === 32) { // Make valid uuid-v4
51
+ // eslint-disable-next-line no-bitwise
52
+ bytes[6] = (bytes[6] & 0x0f) | 0x40;
53
+ // eslint-disable-next-line no-bitwise
54
+ bytes[8] = (bytes[8] & 0x3f) | 0x80;
55
+ }
54
56
  return bytes.toString('hex').substring(0, len);
55
57
  }
56
58