@othree.io/scribe
v3.0.0
Published
Scribe
Downloads
18
Readme
@othree.io/scribe
Function wrapper with lifecycle hooks. Attach callbacks to react when a function is called, completes, or fails — useful for logging, metrics, side effects, or any middleware-style behavior. Includes automatic duration measurement.
Returns Optional<T> from @othree.io/optional, capturing errors instead of throwing.
Install
npm install @othree.io/scribeUsage
Sync
import { scribe } from '@othree.io/scribe'
const result = scribe({
now: Date.now,
fn: (name: string, count: number) => `${name} x${count}`,
transcribeInput: (...args) => console.log('Input:', args),
transcribeOutput: (output, durationMs) => console.log('Output:', output, `(${durationMs}ms)`),
transcribeError: (error, durationMs) => console.error('Error:', error, `(${durationMs}ms)`)
})('Alice', 3)
result.get() // 'Alice x3'Async
import { scribeAsync } from '@othree.io/scribe'
const result = await scribeAsync({
now: Date.now,
fn: async (id: string) => fetchUser(id),
transcribeInput: (id) => logger.info('Fetching user', { id }),
transcribeOutput: (user, durationMs) => logger.info('Fetched user', { user, durationMs }),
transcribeError: (error, durationMs) => logger.error('Fetch failed', { error, durationMs })
})('user-123')
result.map(user => user.name).orElse('Unknown')Minimal (no hooks)
All transcribe callbacks are optional. At minimum, provide now and fn:
const result = scribe({
now: Date.now,
fn: (x: number) => x * 2
})(21)
result.get() // 42Error handling
Errors thrown by fn are captured in the Optional rather than re-thrown:
const result = scribe({
now: Date.now,
fn: () => { throw new Error('boom') },
transcribeError: (error, durationMs) => logger.error(error.message, { durationMs })
})()
result.isEmpty // true
result.getError() // Error('boom')As middleware / side effects
The hooks are not limited to logging. Use them for any side effect that should run at a specific point in the function lifecycle:
const result = scribe({
now: Date.now,
fn: (orderId: string) => processOrder(orderId),
transcribeInput: (orderId) => metrics.increment('orders.started', { orderId }),
transcribeOutput: (order, durationMs) => {
metrics.histogram('orders.duration', durationMs)
cache.set(order.id, order)
},
transcribeError: (error) => alerting.notify('Order processing failed', error)
})('order-456')API
scribe<A, T>(deps: ScribeDeps<A, T>) => (...args: Array<A>) => Optional<T>
Wraps a synchronous function.
scribeAsync<A, T>(deps: ScribeAsyncDeps<A, T>) => (...args: Array<A>) => Promise<Optional<T>>
Wraps an asynchronous function.
Deps
| Property | Type | Required | Description |
|---|---|---|---|
| now | () => number | yes | Clock function for duration measurement (e.g. Date.now) |
| fn | (...args) => T or (...args) => Promise<T> | yes | The function to instrument |
| transcribeInput | (...args) => void | no | Hook called with the original arguments before fn executes |
| transcribeOutput | (output: T, durationMs: number) => void | no | Hook called with the return value and duration when fn succeeds |
| transcribeError | (error: Error, durationMs: number) => void | no | Hook called with the error and duration when fn fails |
Lifecycle
- Record
startTimeviadeps.now() - Call
transcribeInputwith the arguments (if provided) - Execute
fn(wrapped inTry/TryAsync) - Compute
durationMsviadeps.now() - startTime - On success: call
transcribeOutputwith the result and duration - On error: call
transcribeErrorwith the error and duration - Return
Optional<T>containing the result or the captured error
