npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@travetto/runtime

v5.0.13

Published

Runtime for travetto applications.

Downloads

210

Readme

Runtime

Runtime for travetto applications.

Install: @travetto/runtime

npm install @travetto/runtime

# or

yarn add @travetto/runtime

Runtime is the foundation of all Travetto 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:

  • Runtime Context
  • Environment Support
  • Standard Error Support
  • Console Management
  • Resource Access
  • Common Utilities
  • Time Utilities
  • Process Execution
  • Shutdown Management
  • Path behavior

Runtime Context

While running any code within the framework, there are common patterns/goals for interacting with the underlying code repository. These include:

  • Determining attributes of the running environment (e.g., name, debug information, production flags)
  • Resolving paths within the workspace (e.g. standard, tooling, resourcing, modules)

Code: Runtime Shape

class $Runtime {
  constructor(idx: ManifestIndex, resourceOverrides?: Record<string, string>);
  /** Get env name, with support for the default env */
  get env(): string | undefined;
  /** Are we in development mode */
  get production(): boolean;
  /** Is the app in dynamic mode? */
  get dynamic(): boolean;
  /** Get debug value */
  get debug(): false | string;
  /** Manifest main */
  get main(): ManifestContext['main'];
  /** Manifest workspace */
  get workspace(): ManifestContext['workspace'];
  /** Are we running from a mono-root? */
  get monoRoot(): boolean;
  /** Main source path */
  get mainSourcePath(): string;
  /** Produce a workspace relative path */
  workspaceRelative(...rel: string[]): string;
  /** Strip off the workspace path from a file */
  stripWorkspacePath(full: string): string;
  /** Produce a workspace path for tooling, with '@' being replaced by node_module/name folder */
  toolPath(...rel: string[]): string;
  /** Resolve single module path */
  modulePath(modulePath: string): string;
  /** Resolve resource paths */
  resourcePaths(paths: string[] = []): string[];
  /** Get source for function */
  getSourceFile(fn: Function): string;
  /** Get import for function */
  getImport(fn: Function): string;
  /** Import from a given path */
  importFrom<T = unknown>(imp?: string): Promise<T>;
}

Environment Support

The functionality we support for testing and retrieving environment information for known environment variables. They can be accessed directly on the Env object, and will return a scoped EnvProp, that is compatible with the property definition. E.g. only showing boolean related fields when the underlying flag supports true or false

Code: Base Known Environment Flags

interface EnvData {
    /** 
     * The node environment we are running in
     * @default development
     */
    NODE_ENV: 'development' | 'production';
    /** 
     * Outputs all console.debug messages, defaults to `local` in dev, and `off` in prod. 
     */
    DEBUG: boolean | string;
    /** 
     * Environment to deploy, defaults to `NODE_ENV` if not `TRV_ENV` is not specified.  
     */
    TRV_ENV: string;
    /** 
     * Special role to run as, used to access additional files from the manifest during runtime.  
     */
    TRV_ROLE: Role;
    /** 
     * Whether or not to run the program in dynamic mode, allowing for real-time updates  
     */
    TRV_DYNAMIC: boolean;
    /** 
     * The folders to use for resource lookup
     */
    TRV_RESOURCES: string[];
    /** 
     * Resource path overrides
     * @private
     */
    TRV_RESOURCE_OVERRIDES: Record<string, string>;
    /** 
     * The max time to wait for shutdown to finish after initial SIGINT, 
     * @default 2s
     */
    TRV_SHUTDOWN_WAIT: TimeSpan | number;
    /**
     * The desired runtime module 
     */
    TRV_MODULE: string;
    /**
     * The location of the manifest file
     * @default undefined
     */
    TRV_MANIFEST: string;
    /**
     * trvc log level
     */
    TRV_BUILD: 'none' | 'info' | 'debug' | 'error' | 'warn',
    /**
     * Should break on first line of a method when using the @DebugBreak decorator
     * @default false
     */
    TRV_DEBUG_BREAK: boolean;
  }

Environment Property

For a given EnvProp, we support the ability to access different properties as a means to better facilitate environment variable usage.

Code: EnvProp Shape

export class EnvProp<T> {
  constructor(public readonly key: string) { }
  /** Remove value */
  clear(): void;
  /** Export value */
  export(val: T | undefined): Record<string, string>;
  /** Read value as string */
  get val(): string | undefined;
  /** Read value as list */
  get list(): string[] | undefined;
  /** Read value as object */
  get object(): Record<string, string> | undefined;
  /** Add values to list */
  add(...items: string[]): void;
  /** Read value as int  */
  get int(): number | undefined;
  /** Read value as boolean */
  get bool(): boolean | undefined;
  /** Determine if the underlying value is truthy */
  get isTrue(): boolean;
  /** Determine if the underlying value is falsy */
  get isFalse(): boolean;
  /** Determine if the underlying value is set */
  get isSet(): boolean;
}

Standard Error Support

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 (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 module and HTTP status codes).

The AppError takes in a message, and an optional payload and / or error classification. The currently supported error classifications are:

  • general - General purpose errors
  • system - Synonym for general
  • data - Data format, content, etc are incorrect. Generally correlated to bad input.
  • permission - Operation failed due to lack of permissions
  • auth - Operation failed due to lack of authentication
  • missing - Resource was not found when requested
  • timeout - Operation did not finish in a timely manner
  • unavailable - Resource was unresponsive

Console Management

This module provides logging functionality, built upon console operations.

The supported operations are:

  • console.error which logs at the ERROR level
  • console.warn which logs at the WARN level
  • console.info which logs at the INFO level
  • console.debug which logs at the DEBUG level
  • console.log which logs at the INFO level

Note: All other console methods are excluded, specifically trace, inspect, dir, time/timeEnd

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. This module, hooks into the ConsoleManager and receives all logging events from all files compiled by the Travetto.

A sample of the instrumentation would be:

Code: Sample logging at various levels

export function work() {
  console.debug('Start Work');

  try {
    1 / 0;
  } catch (err) {
    console.error('Divide by zero', { error: err });
  }
  console.debug('End Work');
}

Code: Sample After Transpilation

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.work = work;
const tslib_1 = require("tslib");
const Ⲑ_function_1 = tslib_1.__importStar(require("@travetto/runtime/src/function.js"));
const ᚕ_c = tslib_1.__importStar(require("@travetto/runtime/src/console.js"));
var ᚕm = ["@travetto/runtime", "doc/transpile.ts"];
function work() {
    ᚕ_c.log({ level: "debug", import: ᚕm, line: 2, scope: "work", args: ['Start Work'] });
    try {
        1 / 0;
    }
    catch (err) {
        ᚕ_c.log({ level: "error", import: ᚕm, line: 7, scope: "work", args: ['Divide by zero', { error: err }] });
    }
    ᚕ_c.log({ level: "debug", import: ᚕm, line: 9, scope: "work", args: ['End Work'] });
}
Ⲑ_function_1.registerFunction(work, ᚕm, { hash: 1030247697, lines: [1, 10, 2] });

Filtering Debug

The debug messages can be filtered using the patterns from the 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.

Terminal: Sample environment flags


# Debug
$ DEBUG=-@travetto/model npx trv run app
$ DEBUG=-@travetto/registry npx trv run app
$ DEBUG=@travetto/rest npx trv run app
$ DEBUG=@travetto/*,-@travetto/model npx trv run app

Additionally, the logging framework will merge debug into the output stream, and supports the standard usage

Terminal: Sample environment flags for standard usage


# Debug
$ DEBUG=express:*,@travetto/rest npx trv run rest

Resource Access

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's data for what resources were found at manifesting time.

The FileLoader 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 with a category of 'notfound'.

The FileLoader also supports tying itself to Env's TRV_RESOURCES information on where to attempt to find a requested resource.

Common Utilities

Common utilities used throughout the framework. Currently Util 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 '!'.
  • 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.

Code: Sample makeTemplate Usage

const tpl = makeTemplate((name: 'age'|'name', val) => `**${name}: ${val}**`); 
tpl`{{age:20}} {{name: 'bob'}}</>;
// produces
'**age: 20** **name: bob**'

Time Utilities

TimeUtil contains general helper methods, created to assist with time-based inputs via environment variables, command line interfaces, and other string-heavy based input.

Code: Time Utilities

export class TimeUtil {
  /**
   * Test to see if a string is valid for relative time
   * @param val
   */
  static isTimeSpan(val: string): val is TimeSpan;
  /**
   * Returns time units convert to ms
   * @param amount Number of units to extend
   * @param unit Time unit to extend ('ms', 's', 'm', 'h', 'd', 'w', 'y')
   */
  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 fromValue(value: Date | number | string | undefined): number | undefined;
  /**
   * Returns a new date with `amount` units into the future
   * @param amount Number of units to extend
   * @param unit Time unit to extend ('ms', 's', 'm', 'h', 'd', 'w', 'y')
   */
  static fromNow(amount: number | TimeSpan, unit: TimeUnit = 'ms'): Date;
  /**
   * Returns a pretty timestamp
   * @param time Time in milliseconds
   */
  static asClock(time: number): string;
}

Process Execution

ExecUtil exposes getResult as a means to wrap child_process's process object. This wrapper allows for a promise-based resolution of the subprocess with the ability to capture the stderr/stdout.

A simple example would be:

Code: Running a directory listing via ls

import { spawn } from 'node:child_process';
import { ExecUtil } from '@travetto/runtime';

export async function executeListing() {
  const final = await ExecUtil.getResult(spawn('ls'));
  console.log('Listing', { lines: final.stdout.split('\n') });
}

Shutdown Management

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.

As a registered shutdown handler, you can do.

Code: Registering a shutdown handler

import { ShutdownManager } from '@travetto/runtime';

export function registerShutdownHandler() {
  ShutdownManager.onGracefulShutdown(async () => {
    // Do important work, the framework will wait until all async
    //   operations are completed before finishing shutdown
  });
}

Path Behavior

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's path implementation. This allows for seamless import/usage patterns with the reliability needed for cross platform support.