
Security News
Socket for Origin Now Available
Socket for Origin scans dependency changes in pull requests and flags security risks based on your team’s policies. Now available in Cursor’s App Marketplace.
atraceApplication development and telemetry toolkit.
pinoGood error handling is a prerequisite for good logging. To help with this,
atrace provides two simple but powerful building blocks.
The libraryErrorClass function generates a base error class which provides:
import {libraryErrorClass} from 'atrace';
// Flexible error class, allowing arbitrary strings as codes.
const GenericError = libraryErrorClass('my-lib');
const err1 = new GenericError('SOMETHING_FAILED'); // OK.
// Strongly typed error codes.
type ErrorID = 'BAR_MISSING' | 'BAZ_BROKEN';
const SpecificError = libraryErrorClass<ErrorID>('my-lib');
const err2 = new SpecificError('BAR_MISSING'); // OK.
const err3 = new SpecificError('SOMETHING_FAILED'); // Fails (unknown ID).
// For even more customization, you can extend the class as usual.
class CustomError extends libraryErrorClass<ErrorID>('my-lib') {
constructor(id: ErrorID, someData: number) {
super(id, {values: {someData}});
}
// ...
}
const err4 = new CustomError('BAZ_BROKEN', 123);
Beyond the capabilities offered by library errors, applications typically also
need the ability to surface statuses back to the client. As a convenience, the
standardError function is also available to create application errors from a
status.
import {applicationErrorFactory, standardError} from 'atrace';
// For large applications, prefer to create your own error codes:
const newError = applicationErrorFactory('bar', {
'BAD_TOGGLE': 'INVALID_ARGUMENT',
'BOOM': 'INTERNAL',
});
const err1 = newError('BAD_TOGGLE'); // Error with invalid argument status.
// For simple use-cases, you can use the convenience standard errors.
const err2 = standardError('NOT_FOUND');
import {
intSetting,
invalidSource,
settingsProvider,
stringSetting,
} from 'atrace';
const settings = settingsProvider((env) => ({
port: intSetting(env.PORT ?? 8080), // Integer value
auth: { // Hierarchical settings
clientID: stringSetting(env.CLIENT_ID ?? 'my-client'), // String value
clientSecret: stringSetting({
source: env.CLIENT_SECRET ?? invalidSource, // Required string value
sensitive: true, // Redact field from parsed sources
}),
},
tag: stringSetting(env.TAG), // Optional string value
}));
const val = settings(); // Parsed values
Importantly, val's type will automatically be inferred as:
{
readonly port: number;
readonly auth: {
readonly clientID: string;
readonly clientSecret: string;
}
readonly tag: string | undefined;
}
If CLIENT_SECRET wasn't defined in the environment, the config provider will
throw an informative exception. To test different setting values without needing
mocks, pass in a custom environment when calling the config provider.
const val = settings({
CLIENT_ID: 'test-id',
CLIENT_SECRET: 'test-secret',
});
We provide a convenience factory builder for types which do not need any non-standard creation arguments.
import {simpleSettingFactory} from 'atrace';
// A setting which will have values inferred as `Date`s.
const dateSetting = simpleSettingFactory((s): Date => new Date(s));
If additional arguments are desired, it's always possible--just more verbose--to use the underlying setting factory directly. For example, here's one way to implement an enum setting:
import {newSetting, Setting, SettingParams, SettingSource} from 'atrace';
/** Enum setting creation parameters. */
export interface EnumSettingParams<E extends string, S>
extends SettingParams<S> {
/** Allowed enum values. */
readonly symbols: ReadonlyArray<E>;
}
/** Creates a new enum setting. */
export function enumSetting<E extends string, S extends SettingSource>(
params: EnumSettingParams<E, S>
): Setting<S, E> {
return newSetting(params, (s): any => {
if (!~params.symbols.indexOf(s as any)) {
throw new Error('Invalid enum value');
}
return s;
});
}
In production code, we recommend using modular configuration types. Performing
post-processing on setting values is easy with a settingsManager:
// src/config.ts
import {settingsManager} from 'atrace';
// First the (private) underlying settings resource manager.
const withSettings = settingsManager((env) => ({/* ... */}));
// Then the (public) configuration types. These can be different from the raw
// settings for example discriminated unions are often handy. These are meant
// to be used everywhere in the application. Smaller, more specific, types will
// make testing easier and increase modularity.
export interface ModuleAConfig {/* ... */}
export interface ModuleBConfig {/* ... */}
export interface Config {
readonly moduleA: ModuleAConfig;
readonly moduleB: ModuleBConfig;
// ...
}
// Now the (public, though not meant for use everywhere - see below)
// configuration factory. This function should only be imported in the
// application's entry point and this module's unit-tests. Other modules should
// accept already instantiated configuration types, making testing much easier
// and dependencies explicit.
export const config = withSettings((val) => {
// Transform the setting values into the public configuration types...
return {/* ... */};
});
// test/config.test.ts
import * as sut from '../src/config';
// Within a test...
const env = {/* ... */}; // Test environment.
expect(config(env)).toEqual(/* ... */); // Expected config for the environment.
FAQs
Application tracing
The npm package atrace receives a total of 4 weekly downloads. As such, atrace popularity was classified as not popular.
We found that atrace demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.

Security News
Socket for Origin scans dependency changes in pull requests and flags security risks based on your team’s policies. Now available in Cursor’s App Marketplace.

Security News
Agent Baseline’s new reference architecture shows how to secure software factories with four boundaries enforced outside the AI agent.

Security News
arXiv now limits authors to two submissions a month as AI slop overwhelms moderators, delays good papers, and sparks debate over applying the limit to everyone.