# Records API for Bun and Node

Every public class, function and type of the Records engine in `@tinyshed/tinystore`, generated from its source. The [Records guide](https://tinyshed.org/tinystore/docs/guides/records) explains how to use them, and the [Python](https://tinyshed.org/tinystore/docs/reference/python/records), [Go](https://tinyshed.org/tinystore/docs/reference/go/records) and [Rust](https://tinyshed.org/tinystore/docs/reference/rust/records) pages list the same API.

## Level

```ts
type Level = 'debug' | 'info' | 'warn' | 'error' | number
```

A level a logger logs at: one of its four names, or slog's number between them.

## EventLevel

```ts
type EventLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal'
```

An event's level: what loggers and the programs whose lines are kept write.

## Fields

```ts
type Fields = Record<string, unknown> | readonly (readonly [string, unknown])[]
```

What happened, or what it happened in: an object, or its pairs in their order.

## Event

```ts
interface Event {
    /** its time, which the file keeps to the nanosecond */
    at: Date
    stream: string
    /** what happened; `log` for a logger's line */
    name: string
    level?: EventLevel
    message?: string
    /** each value as JSON.parse reads it, an integer past 2^53 a bigint */
    fields: Record<string, unknown>
    context: Record<string, unknown>
    /** 32 hex digits */
    traceId?: string
    /** 16 hex digits */
    spanId?: string
}
```

An event as a read gives it.

## NewEvent

```ts
interface NewEvent {
    name: string
    fields?: Fields
    /** its time: now unless given, from what the stream keeps to ten minutes ahead */
    at?: Date
    context?: Fields
    level?: EventLevel | number
    message?: string
    /** a trace's 32 hex digits, with its span's 16: the current trace's unless given */
    traceId?: string
    spanId?: string
}
```

An event to append: its name, what happened, and what it carries beside.

## AppendOptions

```ts
type AppendOptions = Omit<NewEvent, 'name' | 'fields'>
```

## EventsOptions

```ts
interface EventsOptions {
    /** how long the stream keeps its events: its own, kept in the file; 14 days until one says */
    keep?: Duration
}
```

## Query

```ts
interface Query {
    /** the span before now, '1h'; or from and to */
    since?: Duration
    /** the range's start, included */
    from?: Date
    /** the range's end, excluded */
    to?: Date
    /** any of these streams, for every stream's read */
    streams?: readonly string[]
    /** any of these names: ['log'] is the lines */
    names?: readonly string[]
    /** this level and worse; an event without a level is not found */
    minLevel?: EventLevel
    traceId?: string
    /** each key with this value, by the JSON it was written as, in fields or in context */
    where?: Record<string, unknown>
    /** this text in the message, the name or a value, its case ignored */
    search?: string
    /** newest first; oldest first without it */
    newest?: boolean
    /** the events of a page: 1000, and 10,000 at most */
    limit?: number
    /** a page's next, with the rest of the query as it was */
    after?: string
}
```

What a read finds: every condition given holds; one given as undefined is InvalidError.

## Counted

```ts
type Counted = Omit<Query, 'newest' | 'limit' | 'after'>
```

A query of every event it finds, for what counts them.

## Page

```ts
interface Page {
    events: Event[]
    /** the page after it; the last page has none */
    next?: string
}
```

## Top

```ts
interface Top {
    value: unknown
    count: number
}
```

## Stats

```ts
interface Stats {
    samples: number
    sum: number | bigint
    min: number | bigint
    max: number | bigint
    avg: number
}
```

A field's numbers in a row: a sum of integers exact, a bigint past 2^53.

## Row

```ts
interface Row {
    /** where the row's span begins, counted from 1970 in UTC */
    at: Date
    count: number
    by: Record<string, unknown>
    stats: Record<string, Stats>
    distinct: Record<string, number>
}
```

## Aggregate

```ts
interface Aggregate extends Counted {
    /** the span of a row: the range is one without it */
    every?: Duration
    /** keys whose every value has rows of its own */
    by?: readonly string[]
    /** fields whose numbers a row sums */
    stats?: readonly string[]
    /** fields whose different values a row counts */
    distinct?: readonly string[]
}
```

## StreamInfo

```ts
interface StreamInfo {
    name: string
    keep: DurationText
    /** its oldest event, or where its keep begins while it holds older */
    retainedFrom: Date
    newest: Date
}
```

## PollBatch

```ts
interface PollBatch {
    events: Event[]
    /** where the next poll begins, kept once these events are safe */
    cursor: string
    /** the events keep removed before the cursor reached them */
    expired: number
}
```

## TailQuery

```ts
type TailQuery = Pick<Query, 'streams' | 'names' | 'minLevel' | 'traceId' | 'where' | 'search'>
```

What a tail finds: a query's conditions, and no range, order or limit.

## TailBatch

```ts
interface TailBatch {
    events: Event[]
    /** the events that left the store's hold before the tail read them */
    missed: number
}
```

A tail's batch: the events written since the last, and how many it missed.

## Damage

```ts
interface Damage {
    /** a head row holds events not packed yet, a segment packed ones */
    part: 'head row' | 'segment'
    id: number
    stream: string
    /** its events' oldest and newest times */
    first: Date
    last: Date
    /** what broke */
    error: string
}
```

A head row or a segment that no longer reads, as `damaged` lists it and `drop` takes it.

## Events

```ts
class Events extends Reads {
    readonly stream: string
}
```

A stream of events: written with `append`, which waits for the file, and read back.

### Events.append

```ts
append(name: string, fields?: Fields, options?: AppendOptions): Promise<void>
append(events: readonly NewEvent[]): Promise<void>
```

Writes an event, or a list of them whole or not at all: it returns once
they are written, and a read finds them at once. A refused event names
its place in the list and its name.

### Events.appendLines

```ts
appendLines(lines: readonly ConsoleLine[]): Promise<void>
```

A logger's lines, each an event of this stream.

### Events.lines

```ts
lines(): Lines
```

A writer of another program's output into this stream: each line it is
given becomes an event at the time it arrived, a stack trace's or a JSON
value's lines one, and a write never waits.

```
const out = store.events('worker').lines()
child.stdout.on('data', chunk => out.write(chunk))
child.on('close', () => out.end())
```

## AllEvents

```ts
class AllEvents extends Reads {}
```

Every stream's events, to read: `store.events()`.

### AllEvents.streams

```ts
streams(): Promise<StreamInfo[]>
```

Every stream with events, by name, with what it keeps, where that begins and its newest event's time.

### AllEvents.poll

```ts
poll(cursor?: string, options?: {
        limit?: number
    }): Promise<PollBatch>
```

Every event once, a batch a call, from a cursor the program keeps, the
oldest event kept without one: `{ events, cursor, expired }`. With no
event past the cursor, the batch is empty and its cursor the one given.

### AllEvents.damaged

```ts
damaged(): Promise<Damage[]>
```

What reads met that no longer reads, which `drop` removes: each head
row and segment with its stream and its events' times. What the store
has not met since it opened is not listed.

### AllEvents.drop

```ts
drop(damage: Damage): Promise<void>
```

Removes a head row or a segment that `damaged` listed, so that the
reads over it work again; what still reads is refused.

```
for (const damage of await store.events().damaged()) await store.events().drop(damage)
```

## Lines

```ts
class Lines {}
```

A writer of another program's output into a stream, as `events.lines()`
begins it: each line becomes an event, and a write never waits. It sends
whole lines, so that what it has no room for, `dropped` counts as lines.

### Lines.dropped

```ts
get dropped(): number
```

The lines dropped: past what the writer holds, and, once it ended, by the store.

### Lines.write

```ts
write(chunk: Uint8Array | string): void
```

Takes a piece of output, cut anywhere; it never waits.

### Lines.end

```ts
end(): Promise<void>
```

Ends the writer: what it holds goes, a last line without its newline
too, and it returns once the store wrote them.

## StoreLoggerOptions

```ts
interface StoreLoggerOptions extends LoggerOptions {
    /** how long the stream keeps its events, as store.events takes it */
    keep?: Duration
}
```

What a store's logger is told: a logger's options, and how long its stream keeps.

## LoggerOptions

```ts
interface LoggerOptions {
    /** the lines held between writes; past it a line is dropped and counted: 1024 */
    buffer?: number
    /** the least level a line is kept at; every level when absent */
    level?: Level
    /** how a line is written as it is logged: pretty on a terminal and JSON otherwise when absent */
    console?: ConsoleFormat
    /** how a pretty line shows its time: 'clock' when absent */
    time?: ConsoleTime
    /** leaves the stream out of a pretty line; the record keeps it */
    hideStream?: boolean
    /** where the console lines go: process.stderr when absent */
    to?: ConsoleOut
    /**
     * secrets whose fields are hidden, in the store and on the console, at any
     * depth: a key hides its value when some of its words in a row, written
     * together, are a name's, so 'api key' hides api_key and apiKey; `secrets`
     * holds the usual ones
     */
    redact?: readonly string[]
    /** leaves a URL's password in a value as it is, which is otherwise hidden */
    keepUrlPasswords?: boolean
    /** changes each field's value before it is hidden, kept and shown */
    replace?: (key: string, value: unknown) => unknown
    /**
     * where LOG_LEVEL, LOG_FORMAT and LOG_TIME are read, which win over the
     * options: `env('APP')` reads APP_LOG_LEVEL and the rest, and false
     * reads nothing; the bare names when absent
     */
    env?: EnvLayer | false
    /** adds where each line was logged: source={"function":…,"file":…,"line":…} */
    source?: boolean
}
```

## ConsoleOut

```ts
interface ConsoleOut {
    write(text: string): unknown
    readonly isTTY?: boolean
}
```

Where console lines go: process.stdout, a file's stream, or any other writer.

## logger

```ts
function logger(stream: string, options?: LoggerOptions): Logger
```

A logger of the console alone, for a program that wants the logger and not
the records: its lines are written as a store's logger writes them, and
`store.logger(stream)` in its place keeps them too.

```ts
const log = logger('app', { redact: ['password'] })
const db = log.with({ module: 'db' })   // passed to what needs it
```

## Logger

```ts
class Logger {}
```

A logger of one stream. `info`, `warn` and the rest return at once; a line
goes to the console as it is logged, and becomes a record named `log`, its
message the body, the call's fields its attributes and the fields of `with`
its context, who is speaking.

```ts
const log = store.logger('api')
log.info('server started', { port: 3000 })
log.with({ requestId }).warn('slow request', { ms: 1200 })
log.event('user.created', { userId: 42 })   // a record named for the event
```

### Logger.dropped

```ts
get dropped(): number
```

The lines dropped since the logger began: a full buffer, or a write that
failed. Each is also said on stderr, at most once in ten minutes.

### Logger.debug

```ts
debug(message: string, attrs?: Fields): void
```

### Logger.info

```ts
info(message: string, attrs?: Fields): void
```

### Logger.warn

```ts
warn(message: string, attrs?: Fields): void
```

### Logger.error

```ts
error(message: string, attrs?: Fields): void
```

### Logger.event

```ts
event(name: string, attrs?: Fields): void
```

An event of the stream: a record named for it, with no level and no body.

### Logger.with

```ts
with(context: Fields): Logger
```

The logger of the same stream, buffer and console, its context these fields besides its own.

### Logger.flush

```ts
flush(): Promise<void>
```

Hands what the buffer holds to the server now, as the timer does every second.

### Logger.stop

```ts
stop(): Promise<void>
```

Hands over what the buffer holds and stops the timer; a later line starts it again.

## ConsoleFormat

```ts
type ConsoleFormat = 'pretty' | 'json' | 'off'
```

How a logger writes its lines as they are logged; without one, pretty on a terminal and JSON otherwise.

## ConsoleTime

```ts
type ConsoleTime = 'clock' | 'full' | 'off'
```

How a pretty line shows its time: `11:02:11.123`, `2026-10-02 11:02:11.123 +03:00` or none.

## secrets

```ts
const secrets: readonly string[]
```

The names `redact` takes to hide the usual secrets, as Go's console.Secrets and Python's SECRETS.

## Trace

```ts
interface Trace {
    traceId: Uint8Array | string
    spanId?: Uint8Array | string
}
```

A trace's 16 bytes and the span's 8, as bytes or hex.

## withTrace

```ts
function withTrace<T>(trace: Trace, fn: () => T): T
```

Runs fn in a trace: a logger's lines, and records appended without a trace
of their own, inside it and in what it awaits, take its trace and span.

```ts
await withTrace({ traceId, spanId }, async () => {
  log.info('charged')   // a record of that trace and span
})
```
