Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@travetto/base

Package Overview
Dependencies
Maintainers
0
Versions
357
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@travetto/base - npm Package Compare versions

Comparing version 4.1.2 to 5.0.0-rc.0

2

__index__.ts

@@ -9,7 +9,5 @@ /// <reference path="./src/trv.d.ts" />

export * from './src/shutdown';
export * from './src/stream';
export * from './src/time';
export * from './src/types';
export * from './src/object';
export * from './src/watch';
export * from './src/util';

8

package.json
{
"name": "@travetto/base",
"version": "4.1.2",
"version": "5.0.0-rc.0",
"description": "Environment config and common utilities for travetto applications.",

@@ -27,9 +27,9 @@ "keywords": [

"dependencies": {
"@travetto/manifest": "^4.1.0",
"@travetto/manifest": "^5.0.0-rc.0",
"@types/debug": "^4.1.12",
"@types/node": "^20.14.8",
"@types/node": "^20.14.10",
"debug": "^4.3.5"
},
"peerDependencies": {
"@travetto/transformer": "^4.1.2"
"@travetto/transformer": "^5.0.0-rc.0"
},

@@ -36,0 +36,0 @@ "peerDependenciesMeta": {

@@ -22,4 +22,2 @@ <!-- This file was generated by @travetto/doc and should not be modified directly -->

* Standard Error Support
* Stream Utilities
* Object Utilities
* Common Utilities

@@ -31,3 +29,3 @@ * Time Utilities

## Environment Support
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/base/src/env.ts#L105) object, and will return a scoped [EnvProp](https://github.com/travetto/travetto/tree/main/module/base/src/env.ts#L9), that is compatible with the property definition. E.g. only showing boolean related fields when the underlying flag supports `true` or `false`
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/base/src/env.ts#L116) object, and will return a scoped [EnvProp](https://github.com/travetto/travetto/tree/main/module/base/src/env.ts#L8), that is compatible with the property definition. E.g. only showing boolean related fields when the underlying flag supports `true` or `false`

@@ -63,2 +61,7 @@ **Code: Base Known Environment Flags**

/**
* Resource path overrides
* @private
*/
TRV_RESOURCE_OVERRIDES: Record<string, string>;
/**
* The max time to wait for shutdown to finish after initial SIGINT,

@@ -85,3 +88,3 @@ * @default 2s

### Environment Property
For a given [EnvProp](https://github.com/travetto/travetto/tree/main/module/base/src/env.ts#L9), we support the ability to access different properties as a means to better facilitate environment variable usage.
For a given [EnvProp](https://github.com/travetto/travetto/tree/main/module/base/src/env.ts#L8), we support the ability to access different properties as a means to better facilitate environment variable usage.

@@ -100,2 +103,4 @@ **Code: EnvProp Shape**

get list(): string[] | undefined;
/** Read value as object */
get object(): Record<string, string> | undefined;
/** Add values to list */

@@ -107,4 +112,2 @@ add(...items: string[]): void;

get bool(): boolean | undefined;
/** Read value as a time value */
get time(): number | undefined;
/** Determine if the underlying value is truthy */

@@ -120,3 +123,3 @@ get isTrue(): boolean;

### Runtime Flags
[Env](https://github.com/travetto/travetto/tree/main/module/base/src/env.ts#L105) also provides some convenience methods for common flags used at runtime within the framework. These are wrappers around direct access to `process.env` values with a little bit of logic sprinkled in.
[Env](https://github.com/travetto/travetto/tree/main/module/base/src/env.ts#L116) also provides some convenience methods for common flags used at runtime within the framework. These are wrappers around direct access to `process.env` values with a little bit of logic sprinkled in.

@@ -145,3 +148,8 @@ **Code: Provided Flags**

return (!val && prod()) || IS_FALSE.test(val) ? false : val;
}
},
/** Get resource paths */
get resourcePaths(): string[] {
return [...Env.TRV_RESOURCES.list ?? [], '@#resources', '@@#resources'];
},
});

@@ -153,5 +161,5 @@ ```

The [FileLoader](https://github.com/travetto/travetto/tree/main/module/base/src/file-loader.ts#L12) 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/base/src/error.ts#L13) with a category of 'notfound'.
The [FileLoader](https://github.com/travetto/travetto/tree/main/module/base/src/file-loader.ts#L14) 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/base/src/error.ts#L13) with a category of 'notfound'.
The [ResourceLoader](https://github.com/travetto/travetto/tree/main/module/base/src/resource.ts#L10) extends [FileLoader](https://github.com/travetto/travetto/tree/main/module/base/src/file-loader.ts#L12) and utilizes the [Env](https://github.com/travetto/travetto/tree/main/module/base/src/env.ts#L105)'s `TRV_RESOURCES` information on where to attempt to find a requested resource.
The [FileLoader](https://github.com/travetto/travetto/tree/main/module/base/src/file-loader.ts#L14) also supports tying itself to [Env](https://github.com/travetto/travetto/tree/main/module/base/src/env.ts#L116)'s `TRV_RESOURCES` information on where to attempt to find a requested resource.

@@ -184,3 +192,3 @@ ## Standard Error Support

## How Logging is Instrumented
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/base/src/console.ts#L16). This module, hooks into the [ConsoleManager](https://github.com/travetto/travetto/tree/main/module/base/src/console.ts#L16) and receives all logging events from all files compiled by the [Travetto](https://travetto.dev).
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/base/src/console.ts#L37). This module, hooks into the [ConsoleManager](https://github.com/travetto/travetto/tree/main/module/base/src/console.ts#L37) and receives all logging events from all files compiled by the [Travetto](https://travetto.dev).

@@ -207,3 +215,3 @@ A sample of the instrumentation would be:

Object.defineProperty(exports, "__esModule", { value: true });
exports.work = void 0;
exports.work = work;
const tslib_1 = require("tslib");

@@ -222,3 +230,2 @@ const ᚕ_c = tslib_1.__importStar(require("@travetto/base/src/console.js"));

}
exports.work = work;
```

@@ -248,24 +255,7 @@

## Stream Utilities
The [StreamUtil](https://github.com/travetto/travetto/tree/main/module/base/src/stream.ts#L29) class provides basic stream utilities for use within the framework:
* `toBuffer(src: Readable | Buffer | string): Promise<Buffer>` for converting a stream/buffer/filepath to a Buffer.
* `toReadable(src: Readable | Buffer | string):Promise<Readable>` for converting a stream/buffer/filepath to a Readable
* `writeToFile(src: Readable, out: string):Promise<void>` will stream a readable into a file path, and wait for completion.
## Object Utilities
Simple functions for providing a minimal facsimile to [lodash](https://lodash.com), but without all the weight. Currently [ObjectUtil](https://github.com/travetto/travetto/tree/main/module/base/src/object.ts#L10) includes:
* `isPrimitive(el)` determines if `el` is a `string`, `boolean`, `number` or `RegExp`
* `isPlainObject(obj)` determines if the obj is a simple object
* `isFunction(o)` determines if `o` is a simple `Function`
* `isClass(o)` determines if `o` is a class constructor
* `isSimple(a)` determines if `a` is a simple value
* `isPromise(a)` determines if `a` is a promise
## Common Utilities
Common utilities used throughout the framework. Currently [Util](https://github.com/travetto/travetto/tree/main/module/base/src/util.ts#L12) includes:
Common utilities used throughout the framework. Currently [Util](https://github.com/travetto/travetto/tree/main/module/base/src/util.ts#L17) includes:
* `uuid(len: number)` generates a simple uuid for use within the application.
* `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 '!'.
* `naiveHash(text: string)` produces a fast, and simplistic hash. No guarantees are made, but performs more than adequately for framework purposes.
* `shortHash(text: string)` produces a sha512 hash and returns the first 32 characters.
* `fullHash(text: string, size?: number)` produces a full sha512 hash.
* `hash(text: string, size?: number)` produces a full sha512 hash.
* `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.

@@ -282,3 +272,3 @@

## Time Utilities
[TimeUtil](https://github.com/travetto/travetto/tree/main/module/base/src/time.ts#L19) contains general helper methods, created to assist with time-based inputs via environment variables, command line interfaces, and other string-heavy based input.
[TimeUtil](https://github.com/travetto/travetto/tree/main/module/base/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.

@@ -298,7 +288,17 @@ **Code: Time Utilities**

*/
static timeToMs(amount: number | TimeSpan, unit?: TimeUnit): number;
static asMillis(amount: Date | number | TimeSpan, unit?: TimeUnit): number;
/**
* Returns the time converted to seconds
* @param date The date to convert
*/
static asSeconds(date: Date | number | TimeSpan, unit?: TimeUnit): number;
/**
* Returns the time converted to a Date
* @param date The date to convert
*/
static asDate(date: Date | number | TimeSpan, unit?: TimeUnit): Date;
/**
* Resolve time or span to possible time
*/
static resolveInput(value: number | string | undefined): number | undefined;
static fromValue(value: Date | number | string | undefined): number | undefined;
/**

@@ -309,12 +309,8 @@ * Returns a new date with `amount` units into the future

*/
static timeFromNow(amount: number | TimeSpan, unit: TimeUnit = 'ms'): Date;
static fromNow(amount: number | TimeSpan, unit: TimeUnit = 'ms'): Date;
/**
* Pretty print a delta between now and `time`, with auto-detection of largest unit
* Returns a pretty timestamp
* @param time Time in milliseconds
*/
static prettyDeltaSinceTime(time: number, unit?: TimeUnit): string;
/**
* Pretty print a delta, with auto-detection of largest unit
* @param delta The number of milliseconds in the delta
*/
static prettyDelta(delta: number, unit?: TimeUnit): string;
static asClock(time: number): string;
}

@@ -321,0 +317,0 @@ ```

@@ -6,4 +6,25 @@ import util from 'node:util';

import type { ConsoleListener, ConsoleEvent, LogLevel } from './types';
export type ConsoleEvent = {
/** Time of event */
timestamp: Date;
/** The level of the console event */
level: 'info' | 'warn' | 'debug' | 'error';
/** The source file of the event */
source: string;
/** The line number the console event was triggered from */
line: number;
/** The module name for the source file */
module: string;
/** The module path for the source file*/
modulePath: string;
/** The computed scope for the console. statement. */
scope?: string;
/** Arguments passed to the console call*/
args: unknown[];
};
export interface ConsoleListener {
log(ev: ConsoleEvent): void;
}
const DEBUG_OG = { formatArgs: debug.formatArgs, log: debug.log };

@@ -17,10 +38,5 @@

*/
class $ConsoleManager {
class $ConsoleManager implements ConsoleListener {
/**
* Stack of nested listeners
*/
#stack: ConsoleListener[] = [];
/**
* The current listener

@@ -33,6 +49,6 @@ */

*/
#filters: Partial<Record<LogLevel, (x: ConsoleEvent) => boolean>> = {};
#filters: Partial<Record<ConsoleEvent['level'], (x: ConsoleEvent) => boolean>> = {};
constructor(listener: ConsoleListener) {
this.set(listener, true);
this.set(listener);
this.enhanceDebug(true);

@@ -47,3 +63,3 @@ this.debug(false);

*/
filter(level: LogLevel, filter?: boolean | ((ctx: ConsoleEvent) => boolean)): void {
filter(level: ConsoleEvent['level'], filter?: boolean | ((ctx: ConsoleEvent) => boolean)): void {
if (filter !== undefined) {

@@ -64,4 +80,4 @@ if (typeof filter === 'boolean') {

enhanceDebug(active: boolean): void {
Error.stackTraceLimit = active ? 50 : 10;
if (active) {
Error.stackTraceLimit = 50;
debug.formatArgs = function (args: string[]): void {

@@ -71,3 +87,3 @@ args.unshift(this.namespace);

};
debug.log = (modulePath, ...args: string[]): void => this.invoke({
debug.log = (modulePath, ...args: string[]): void => this.log({
level: 'debug', module: '@npm:debug', modulePath,

@@ -77,3 +93,2 @@ args: [util.format(...args)], line: 0, source: '', timestamp: new Date()

} else {
Error.stackTraceLimit = 10;
debug.formatArgs = DEBUG_OG.formatArgs;

@@ -100,3 +115,3 @@ debug.log = DEBUG_OG.log;

*/
invoke(ev: ConsoleEvent): void {
log(ev: ConsoleEvent): void {
// Resolve input to source file

@@ -116,3 +131,3 @@ const source = ev.source ? RuntimeIndex.getSourceFile(ev.source) : RuntimeIndex.mainModule.outputPath;

} else {
return this.#listener.onLog(outEv);
return this.#listener.log(outEv);
}

@@ -122,25 +137,17 @@ }

/**
* Set a new console listener, works as a stack to allow for nesting
* Set a new console listener
*/
set(cons: ConsoleListener, replace = false): void {
if (!replace) {
this.#stack.unshift(cons);
} else {
this.#stack[0] = cons;
}
this.#listener = this.#stack[0];
set(cons: ConsoleListener): void {
this.#listener = cons;
}
/**
* Pop off the logging stack
* Get the listener
*/
clear(): void {
if (this.#stack.length > 1) {
this.#stack.shift();
this.#listener = this.#stack[0];
}
get(): ConsoleListener {
return this.#listener;
}
}
export const ConsoleManager = new $ConsoleManager({ onLog: (ev): void => { console![ev.level](...ev.args); } });
export const log = ConsoleManager.invoke.bind(ConsoleManager);
export const ConsoleManager = new $ConsoleManager({ log(ev): void { console![ev.level](...ev.args); } });
export const log = ConsoleManager.log.bind(ConsoleManager);
/// <reference path="./trv.d.ts" />
import { RuntimeContext } from '@travetto/manifest';
import { TimeSpan, TimeUtil } from './time';

@@ -28,3 +27,14 @@ const IS_TRUE = /^(true|yes|on|1)$/i;

export(val: T | undefined): Record<string, string> {
return val === undefined || val === '' ? { [this.key]: '' } : { [this.key]: Array.isArray(val) ? `${val.join(',')}` : `${val}` };
let out: string;
if (val === undefined || val === '' || val === null) {
out = '';
} else if (Array.isArray(val)) {
out = val.join(',');
} else if (typeof val === 'object') {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
out = Object.entries(val as Record<string, string>).map(([k, v]) => `${k}=${v}`).join(',');
} else {
out = `${val}`;
}
return { [this.key]: out };
}

@@ -42,2 +52,8 @@

/** Read value as object */
get object(): Record<string, string> | undefined {
const items = this.list;
return items ? Object.fromEntries(items.map(x => x.split(/[:=]/g))) : undefined;
}
/** Add values to list */

@@ -61,7 +77,2 @@ add(...items: string[]): void {

/** Read value as a time value */
get time(): number | undefined {
return TimeUtil.resolveInput(this.val);
}
/** Determine if the underlying value is truthy */

@@ -87,5 +98,5 @@ get isTrue(): boolean {

(TravettoEnv[K] extends unknown[] ? 'list' | 'add' : never) |
(Extract<TravettoEnv[K], object> extends never ? never : 'object') |
(Extract<TravettoEnv[K], number> extends never ? never : 'int') |
(Extract<TravettoEnv[K], boolean> extends never ? never : 'bool' | 'isTrue' | 'isFalse') |
(Extract<TravettoEnv[K], TimeSpan> extends never ? never : 'time')
(Extract<TravettoEnv[K], boolean> extends never ? never : 'bool' | 'isTrue' | 'isFalse')
>

@@ -129,3 +140,8 @@ };

return (!val && prod()) || IS_FALSE.test(val) ? false : val;
}
},
/** Get resource paths */
get resourcePaths(): string[] {
return [...Env.TRV_RESOURCES.list ?? [], '@#resources', '@@#resources'];
},
});

@@ -15,14 +15,16 @@ export type ErrorCategory =

/** Is the object in the shape of an error */
static isErrorLike(val: unknown): val is AppError {
return !!val && (typeof val === 'object' || typeof val === 'function') &&
'message' in val && 'category' in val && 'type' in val && 'at' in val;
}
/** Convert from JSON object */
static fromErrorLike(e: AppError): AppError {
const err = new AppError(e.message, e.category, e.details);
err.at = e.at;
err.type = e.type;
return err;
static fromJSON(e: unknown): AppError | undefined {
if (!!e && typeof e === 'object' &&
('message' in e && typeof e.message === 'string') &&
('category' in e && typeof e.category === 'string') &&
('type' in e && typeof e.type === 'string') &&
('at' in e && typeof e.at === 'number')
) {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const err = new AppError(e.message, e.category as ErrorCategory, 'details' in e ? e.details : undefined);
err.at = new Date(e.at);
err.type = e.type;
return err;
}
}

@@ -40,3 +42,2 @@

* @param details Optional error payload
* @param stack A stack to override if needed
*/

@@ -46,4 +47,3 @@ constructor(

public category: ErrorCategory = 'general',
details?: T,
stack?: string
details?: T

@@ -53,3 +53,2 @@ ) {

this.type = this.constructor.name;
this.stack = stack || this.stack;
this.details = details!;

@@ -60,5 +59,4 @@ }

* The format of the JSON output
* @param extra Extra data to build into the context
*/
toJSON(): unknown {
toJSON(): { message: string, category: string, type: string, at: number, details?: Record<string, unknown> } {
return {

@@ -68,6 +66,7 @@ message: this.message,

type: this.type,
at: this.at,
details: this.details,
at: this.at.getTime(),
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
details: this.details as Record<string, unknown>,
};
}
}

@@ -25,11 +25,11 @@ import { ChildProcess } from 'node:child_process';

*/
export interface ExecutionResult extends ExecutionBaseResult {
export interface ExecutionResult<T extends string | Buffer = string | Buffer> extends ExecutionBaseResult {
/**
* Stdout as a string
* Stdout
*/
stdout: string;
stdout: T;
/**
* Stderr as a string
* Stderr
*/
stderr: string;
stderr: T;
}

@@ -44,7 +44,2 @@

/** Listen for disconnect, and exit if needed */
static exitOnDisconnect(): void {
process.once('disconnect', () => process.exit());
}
/**

@@ -97,7 +92,8 @@ * Run with automatic restart support

*/
static getResult(
proc: ChildProcess & { [RESULT]?: Promise<ExecutionResult> },
options: { catch?: boolean } = {}
): Promise<ExecutionResult> {
const res = proc[RESULT] ??= new Promise<ExecutionResult>(resolve => {
static getResult(proc: ChildProcess): Promise<ExecutionResult<string>>;
static getResult(proc: ChildProcess, options: { catch?: boolean, binary?: false }): Promise<ExecutionResult<string>>;
static getResult(proc: ChildProcess, options: { catch?: boolean, binary: true }): Promise<ExecutionResult<Buffer>>;
static getResult<T extends string | Buffer>(proc: ChildProcess, options: { catch?: boolean, binary?: boolean } = {}): Promise<ExecutionResult<T>> {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const res = (proc as unknown as { [RESULT]: Promise<ExecutionResult> })[RESULT] ??= new Promise<ExecutionResult>(resolve => {
const stdout: Buffer[] = [];

@@ -112,5 +108,10 @@ const stderr: Buffer[] = [];

const buffers = {
stdout: Buffer.concat(stdout),
stderr: Buffer.concat(stderr),
};
const final = {
stdout: Buffer.concat(stdout).toString('utf8'),
stderr: Buffer.concat(stderr).toString('utf8'),
stdout: options.binary ? buffers.stdout : buffers.stdout.toString('utf8'),
stderr: options.binary ? buffers.stderr : buffers.stderr.toString('utf8'),
...result

@@ -139,3 +140,4 @@ };

return options.catch ? res : res.then(v => {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return (options.catch ? res : res.then(v => {
if (v.valid) {

@@ -146,4 +148,4 @@ return v;

}
});
})) as Promise<ExecutionResult<T>>;
}
}
import { createReadStream } from 'node:fs';
import { Readable } from 'node:stream';
import fs from 'node:fs/promises';
import path from 'node:path';
import { path, RuntimeIndex } from '@travetto/manifest';
import { RuntimeIndex } from '@travetto/manifest';
import { AppError } from './error';
import { Env } from './env';
/**
* File loader that will search for relative paths across the provided search paths
* File loader that will search for files across the provided search paths
*/

@@ -17,6 +19,12 @@ export class FileLoader {

static resolvePaths(paths: string[]): string[] {
return [...new Set(paths.map(x => RuntimeIndex.resolveModulePath(x)))];
const overrides = Env.TRV_RESOURCE_OVERRIDES.object ?? {};
return [...new Set(paths.map(x => RuntimeIndex.resolveModulePath(overrides[x] ?? x)))];
}
constructor(paths: string[]) {
this.computePaths(paths);
}
/** @private */
protected computePaths(paths: string[]): void {
this.#searchPaths = Object.freeze(FileLoader.resolvePaths(paths));

@@ -23,0 +31,0 @@ }

import { Env } from './env';
import { FileLoader } from './file-loader';
const RES = Env.TRV_RESOURCES;
const COMMON = ['@#resources', '@@#resources'];
/**
* File-based resource loader
*/
export class ResourceLoader extends FileLoader {
constructor(paths?: string[] | readonly string[]) {
super([...paths ?? [], ...RES.list ?? [], ...COMMON]);
}
}
class $RuntimeResources extends FileLoader {
#env: string = '__';
#paths: readonly string[];
get searchPaths(): readonly string[] {
if (this.#env !== RES.val) {
this.#env = RES.val!;
this.#paths = Object.freeze(FileLoader.resolvePaths([...RES.list ?? [], ...COMMON]));
#env: string;
override get searchPaths(): readonly string[] {
if (this.#env !== Env.TRV_RESOURCES.val) {
this.#env = Env.TRV_RESOURCES.val!;
this.computePaths(Env.resourcePaths);
}
return this.#paths;
return super.searchPaths;
}
}
/** Resources available at runtime, updates in realtime with changes to process.env.TRV_RESOURCES */
export const RuntimeResources = new $RuntimeResources([]);
export const RuntimeResources = new $RuntimeResources(Env.resourcePaths);
import { Env } from './env';
import { Util } from './util';
import { TimeUtil } from './time';

@@ -35,3 +36,3 @@ /**

*/
static async gracefulShutdown(code: number | undefined = process.exitCode): Promise<void> {
static async gracefulShutdown(code: number | string | undefined = process.exitCode): Promise<void> {
if (code !== undefined) {

@@ -55,3 +56,3 @@ process.exitCode = code;

await Promise.race([
Util.nonBlockingTimeout(Env.TRV_SHUTDOWN_WAIT.time ?? 2000), // Wait 2s and then force finish
Util.nonBlockingTimeout(TimeUtil.fromValue(Env.TRV_SHUTDOWN_WAIT.val) ?? 2000), // Wait 2s and then force finish
handlers,

@@ -58,0 +59,0 @@ ]);

@@ -14,4 +14,2 @@ const MIN = 1000 * 60;

const ORDER = ['ms', 's', 'm', 'h', 'd', 'w', 'M', 'y'] as const;
export type TimeSpan = `${number}${keyof typeof TIME_UNITS}`;

@@ -37,4 +35,6 @@ export type TimeUnit = keyof typeof TIME_UNITS;

*/
static timeToMs(amount: number | TimeSpan, unit?: TimeUnit): number {
if (typeof amount === 'string') {
static asMillis(amount: Date | number | TimeSpan, unit?: TimeUnit): number {
if (amount instanceof Date) {
return amount.getTime();
} else if (typeof amount === 'string') {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions

@@ -53,11 +53,28 @@ const { groups } = (amount.match(this.#timePattern) as { groups: { amount?: string, unit?: TimeUnit } });

/**
* Returns the time converted to seconds
* @param date The date to convert
*/
static asSeconds(date: Date | number | TimeSpan, unit?: TimeUnit): number {
return Math.trunc(this.asMillis(date, unit) / 1000);
}
/**
* Returns the time converted to a Date
* @param date The date to convert
*/
static asDate(date: Date | number | TimeSpan, unit?: TimeUnit): Date {
return new Date(this.asMillis(date, unit));
}
/**
* Resolve time or span to possible time
*/
static resolveInput(value: number | string | undefined): number | undefined {
static fromValue(value: Date | number | string | undefined): number | undefined {
if (value === undefined) {
return value;
}
const val = (typeof value === 'string' && /\d+[a-z]+$/i.test(value)) ?
(this.isTimeSpan(value) ? this.timeToMs(value) : undefined) :
(typeof value === 'string' ? parseInt(value, 10) : value);
const val = (typeof value === 'string' && /\d+[a-z]$/i.test(value)) ?
(this.isTimeSpan(value) ? this.asMillis(value) : undefined) :
(typeof value === 'string' ? parseInt(value, 10) :
(value instanceof Date ? value.getTime() : value));
return Number.isNaN(val) ? undefined : val;

@@ -71,59 +88,18 @@ }

*/
static timeFromNow(amount: number | TimeSpan, unit: TimeUnit = 'ms'): Date {
return new Date(Date.now() + this.timeToMs(amount, unit));
static fromNow(amount: number | TimeSpan, unit: TimeUnit = 'ms'): Date {
return new Date(Date.now() + this.asMillis(amount, unit));
}
/**
* Pretty print a delta between now and `time`, with auto-detection of largest unit
* Returns a pretty timestamp
* @param time Time in milliseconds
*/
static prettyDeltaSinceTime(time: number, unit?: TimeUnit): string {
return this.prettyDelta(Date.now() - time, unit);
static asClock(time: number): string {
const s = Math.trunc(time / 1000);
return [
s > 3600 ? `${Math.trunc(s / 3600).toString().padStart(2, '0')}h` : '',
s > 60 ? `${Math.trunc((s % 3600) / 60).toString().padStart(2, '0')}m` : '',
`${(s % 60).toString().padStart(2, '0')}s`
].filter(x => !!x).slice(0, 2).join(' ');
}
/**
* Pretty print a delta, with auto-detection of largest unit
* @param delta The number of milliseconds in the delta
*/
static prettyDelta(delta: number, unit?: TimeUnit): string {
if (delta === 0) {
return `0${unit}`;
} else if (delta < 0) {
return `-${this.prettyDelta(-delta, unit)}`;
}
let idx: number = 0;
if (!unit) {
let i = 0;
while (delta > TIME_UNITS[ORDER[i]]) {
i += 1;
}
idx = i - 1;
} else {
idx = ORDER.indexOf(unit);
}
const majorUnit = TIME_UNITS[ORDER[idx]];
const minorUnit = TIME_UNITS[ORDER[idx - 1]];
const value = delta / majorUnit;
const major = Math.trunc(value);
if (unit === undefined && value < 1.25 && idx > 0) {
return this.prettyDelta(delta, ORDER[idx - 1]);
}
const sub = value - major;
const out: (string | number)[] = [major, ORDER[idx]];
if (idx > 0 && sub > .01) {
const minor = Math.trunc(sub * (majorUnit / minorUnit));
out.push(' ', minor, ORDER[idx - 1]);
}
return out.join('');
}
/**
* Determine the number of units between two dates
*/
static unitsBetween(startDate: Date | number, endDate: Date | number, unit: TimeUnit): number {
const delta =
(typeof endDate === 'number' ? endDate : endDate.getTime()) -
(typeof startDate === 'number' ? startDate : startDate.getTime());
return delta / TIME_UNITS[unit];
}
}

@@ -35,2 +35,7 @@ import { ManifestModuleRole } from '@travetto/manifest';

/**
* Resource path overrides
* @private
*/
TRV_RESOURCE_OVERRIDES: Record<string, string>;
/**
* The max time to wait for shutdown to finish after initial SIGINT,

@@ -37,0 +42,0 @@ * @default 2s

@@ -8,32 +8,2 @@ /* eslint-disable @typescript-eslint/no-explicit-any */

export type Primitive = number | boolean | string | Date;
export type LogLevel = 'info' | 'warn' | 'debug' | 'error';
export type ConsoleEvent = {
/** Time of event */
timestamp: Date;
/** The level of the console event */
level: LogLevel;
/** The source file of the event */
source: string;
/** The line number the console event was triggered from */
line: number;
/** The module name for the source file */
module: string;
/** The module path for the source file*/
modulePath: string;
/** The computed scope for the console. statement. */
scope?: string;
/** Arguments passed to the console call*/
args: unknown[];
};
export interface ConsoleListener {
onLog(ev: ConsoleEvent): void;
}
/* eslint-disable @typescript-eslint/no-explicit-any */
export type MethodDescriptor<R = any, V = unknown> = TypedPropertyDescriptor<(this: V, ...params: any[]) => R>;
export const TypedObject: {

@@ -40,0 +10,0 @@ keys<T = unknown, K extends keyof T = keyof T>(o: T): K[];

import crypto from 'node:crypto';
import timers from 'node:timers/promises';
import fs from 'node:fs/promises';
import path from 'node:path';
import { ManifestFileUtil } from '@travetto/manifest';
type PromiseWithResolvers<T> = {
resolve: (v: T) => void;
reject: (err?: unknown) => void;
promise: Promise<T>;
};
type PromiseResolver<T> = { resolve: (v: T) => void, reject: (err?: unknown) => void };
type MapFn<T, U> = (val: T, i: number) => U | Promise<U>;

@@ -32,3 +37,3 @@

*/
static fullHash(src: string, len: number = -1): string {
static hash(src: string, len: number = -1): string {
const hash = crypto.createHash('sha512');

@@ -41,30 +46,8 @@ hash.update(src);

/**
* Generate a short hash from a src value, based on sha512
* @param src The seed value to build the hash from
*/
static shortHash(src: string): string {
return this.fullHash(src, 32);
}
/**
* Naive hashing
*/
static naiveHash(text: string): number {
let hash = 5381;
for (let i = 0; i < text.length; i++) {
// eslint-disable-next-line no-bitwise
hash = (hash * 33) ^ text.charCodeAt(i);
}
return Math.abs(hash);
}
/**
* Produce a promise that is externally resolvable
*/
static resolvablePromise<T = void>(): Promise<T> & PromiseResolver<T> {
let ops: PromiseResolver<T>;
static resolvablePromise<T = void>(): PromiseWithResolvers<T> {
let ops: Pick<PromiseWithResolvers<T>, 'reject' | 'resolve'>;
const prom = new Promise<T>((resolve, reject) => ops = { resolve, reject });
return Object.assign(prom, ops!);
return { ...ops!, promise: prom };
}

@@ -94,6 +77,18 @@

/**
* Consume an async iterator without the need for declaring a function
*/
static async consumeAsyncItr<T>(source: AsyncIterable<T>, handler: (input: T) => unknown | Promise<unknown>): Promise<void> {
for await (const item of source) {
await handler(item);
}
}
/**
* Write file and copy over when ready
*/
static async bufferedFileWrite(file: string, content: string | object): Promise<string> {
return ManifestFileUtil.bufferedFileWrite(file, content);
static async bufferedFileWrite(file: string, content: string): Promise<void> {
const temp = path.resolve(path.dirname(file), `.${process.hrtime()[0]}.${path.basename(file)}`);
await fs.mkdir(path.dirname(file), { recursive: true });
await fs.writeFile(temp, content, 'utf8');
await fs.rename(temp, file);
}

@@ -100,0 +95,0 @@

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc