@wireio/shared
v1.0.6
Published
Core shared utilities for Wire applications, providing a logging framework, type guards, and async helpers that work across browser and Node.js environments.
Readme
@wireio/shared
Core shared utilities for Wire applications, providing a logging framework, type guards, and async helpers that work across browser and Node.js environments.
Installation
pnpm add @wireio/sharedModules
- Logging - Flexible logging framework with multiple appenders
- Guards - Type guards and assertion utilities
- Helpers - Async utilities including
Deferred
Logging
A flexible, extensible logging framework supporting multiple log levels, appenders, and contextual logging.
Basic Usage
import { getLoggingManager } from "@wireio/shared"
const logManager = getLoggingManager()
const log = logManager.getLogger("my-module")
log.trace("Detailed trace message")
log.debug("Debug information")
log.info("Informational message")
log.warn("Warning message")
log.error("Error occurred", new Error("Something went wrong"))
log.fatal("Fatal error - application cannot continue")Log Levels
Levels are ordered by severity (lowest to highest):
| Level | Threshold | Description |
|-------|-----------|-------------|
| trace | 0 | Fine-grained debugging |
| debug | 1 | Debugging information |
| info | 2 | Informational messages |
| warn | 3 | Warning conditions |
| error | 4 | Error conditions |
| fatal | 5 | Critical failures |
Configuring the Logging Manager
import { getLoggingManager, Level, ConsoleAppender } from "@wireio/shared"
const logManager = getLoggingManager()
// Set the root logging level
logManager.setRootLevel(Level.debug)
// Replace default appenders
logManager.setAppenders(new ConsoleAppender({ prettyPrint: true }))
// Add additional appenders
logManager.addAppenders(new MyCustomAppender())
// Configure threshold overrides for specific categories
logManager.addThresholdOverrides(
[/^database/, "debug"], // Enable debug for database.* categories
["auth", "trace"] // Enable trace for exact "auth" category
)Environment-Based Debug Patterns
Set the DEBUG_PATTERNS environment variable to enable debug logging for specific categories:
DEBUG_PATTERNS="database.*,auth.*" node app.jsLevel Checking
Check if a level is enabled before expensive operations:
if (log.isDebugEnabled()) {
log.debug("Expensive data:", computeExpensiveDebugInfo())
}Log Records
Each log record contains:
interface LogRecord {
timestamp: number // EPOCH Milliseconds
category: string // Logger category
level: LevelKind // Log level
message: string // Log message
args?: any[] // Additional arguments
data?: any // Structured data
tags?: string[] // Tags for filtering
url?: string // Source URL (auto-populated)
env?: string // Environment (auto-populated)
errorMessage?: string // Error message (if Error passed)
errorStack?: string // Error stack trace (if Error passed)
}Built-in Appenders
ConsoleAppender
Default appender that writes to the console:
import { ConsoleAppender } from "@wireio/shared"
const appender = new ConsoleAppender({
prettyPrint: true,
formatter: ({ level, message, category }) =>
`[${category}] (${level}) ${message}`
})AWSFirehoseAppender
Streams logs to AWS Kinesis Data Firehose for centralized log aggregation:
import { AWSFirehoseAppender, AWSFirehoseCredentialManager } from "@wireio/shared"
const credManager = new AWSFirehoseCredentialManager()
const firehoseAppender = new AWSFirehoseAppender(credManager)
logManager.addAppenders(firehoseAppender)Features:
- Automatic credential refresh before expiration (3-minute buffer)
- Batched record delivery (up to 10 records per batch)
- Queue management with 10,000 record limit (oldest records dropped when exceeded)
- Automatic retry on expired token errors
- Event-driven credential handling via EventEmitter3
Credential Manager Events:
credManager.on("received", (creds) => {
console.log("Credentials received, stream:", creds.streamName)
})
credManager.on("expired", () => {
console.log("Credentials expired")
})AWS Credentials Structure:
interface AWSCredentials {
accessKeyId: string
secretAccessKey: string
sessionToken: string
streamName: string // Firehose delivery stream name
region: string // AWS region
expiration: string // ISO 8601 expiration timestamp
}The credential manager fetches temporary credentials from an HTTP endpoint and automatically schedules refresh before expiration.
Custom Appenders
Implement the Appender interface:
import { Appender, LogRecord } from "@wireio/shared"
class MyCustomAppender implements Appender {
append(record: LogRecord): void {
// Send to external service, write to file, etc.
}
}Guards
Type guards and assertion utilities for runtime type checking with TypeScript type narrowing.
Primitive Guards
import {
isString, isNumber, isBoolean, isFunction,
isObject, isArray, isNil, isDefined, isPromise
} from "@wireio/shared"
if (isString(value)) {
// value is narrowed to string
console.log(value.toUpperCase())
}
if (isDefined(maybeNull)) {
// maybeNull is narrowed to exclude null/undefined
}
if (isPromise(result)) {
// result is narrowed to Promise<any>
await result
}Available Guards
| Guard | Type Narrowing |
|-------|----------------|
| isNil(o) | undefined \| null |
| isDefined(o) | Excludes undefined \| null |
| isString(o) | string |
| isNumber(o) | number (excludes NaN) |
| isBoolean(o) | boolean |
| isFunction(o) | Function |
| isObject(o) | Object |
| isArray(o) | Array<T> |
| isPromise(o) | Promise<any> |
| isSymbol(o) | Symbol |
| isDate(o) | Date |
| isPrimitive(o) | boolean \| string \| number |
Assertions
import { assert, AssertError } from "@wireio/shared"
// Throws AssertError if condition is false
assert(user !== null, "User must be defined")
// With function condition
assert(() => array.length > 0, "Array must not be empty")
// Lifted assertions for reuse
const assertPositive = assert.lift(
(n: number) => n > 0,
(n) => `Expected positive number, got ${n}`
)
assertPositive(5) // OK
assertPositive(-1) // Throws AssertErrorSafe Value Access
import { getValue, guard } from "@wireio/shared"
// Get value with fallback on error
const name = getValue(() => user.profile.name, "Unknown")
// Execute function, swallow errors
guard(() => riskyOperation())
// With error handler
guard(() => riskyOperation(), (err) => console.error(err))Deferred (a Promise you manage)
A Deferred is a Promise that can be resolved or rejected externally, useful for coordinating async operations.
import { Deferred, DeferredStatus } from "@wireio/shared"
// Create a deferred promise
const deferred = new Deferred<string>()
// Resolve it later
setTimeout(() => deferred.resolve("done"), 1000)
// Await the promise
const result = await deferred.promiseDeferred API
// Create with optional existing promise to wrap
const deferred = new Deferred<T>(existingPromise?)
// The underlying promise
deferred.promise: Promise<T>
// Resolve the promise
deferred.resolve(value?: T): void
// Reject the promise
deferred.reject(error: any): void
// Cancel (prevents future resolve/reject)
deferred.cancel(): void
// Status checks
deferred.isFulfilled(): boolean
deferred.isRejected(): boolean
deferred.isSettled(): boolean
deferred.isCancelled(): boolean
deferred.status(): DeferredStatus
// Get result (throws if not settled)
deferred.value: T
deferred.error: Error | undefinedStatic Methods
// Create an already-resolved Deferred
const resolved = Deferred.resolve("value")
// Delay utility
await Deferred.delay(1000) // Wait 1 secondUse Cases
Timeout wrapper:
async function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {
const deferred = new Deferred<T>()
const timer = setTimeout(() => deferred.reject(new Error("Timeout")), ms)
promise
.then((v) => { clearTimeout(timer); deferred.resolve(v) })
.catch((e) => { clearTimeout(timer); deferred.reject(e) })
return deferred.promise
}Coordination:
class ResourceLoader {
private loadDeferred: Deferred<Resource> | null = null
async load(): Promise<Resource> {
if (this.loadDeferred) return this.loadDeferred.promise
this.loadDeferred = new Deferred()
try {
const resource = await fetchResource()
this.loadDeferred.resolve(resource)
} catch (e) {
this.loadDeferred.reject(e)
}
return this.loadDeferred.promise
}
}API Reference
Logging Exports
import {
// Manager
LoggingManager,
getLoggingManager,
// Logger
Logger,
LoggerOptions,
// Levels
Level,
LevelKind,
LevelNames,
LevelThresholds,
// Records
LogRecord,
// Appenders
Appender,
ConsoleAppender,
DebugAppender,
AWSFirehoseAppender,
// Formatters
Formatter,
} from "@wireio/shared"Guards Exports
import {
// Primitives
isNil, isDefined, isString, isNumber, isBoolean,
isFunction, isObject, isArray, isPromise, isSymbol,
isDate, isPrimitive,
// Assertions
assert, AssertError,
// Utilities
getValue, guard,
} from "@wireio/shared"Helpers Exports
import { Deferred, DeferredStatus } from "@wireio/shared"