Skip to content

Typed Buckets

Buckets are gunsole’s core abstraction for grouping logs. Pass buckets in your config to get first-class typed accessors with full autocomplete.

import { createGunsoleClient } from "@gunsole/web";
const gunsole = createGunsoleClient({
projectId: "my-app",
mode: "local",
buckets: ["auth", "payments", "api", "ui", "database"] as const,
// ^^^^^^^^
// `as const` is required for type inference
});

Direct call logs at info level. Each bucket also has level sub-methods:

// Direct call — logs at "info" level
gunsole.auth("User logged in");
// Level sub-methods
gunsole.auth.info("User logged in");
gunsole.auth.debug("Token refresh started");
gunsole.auth.warn("Token expires in 5 minutes");
gunsole.auth.error("Login failed", {
context: { reason: "invalid_password" },
tags: { method: "oauth" },
});
gunsole.auth.fatal("Auth service unreachable");
gunsole.payments("Checkout completed", {
context: { amount: 99.99, currency: "USD" },
tags: { provider: "stripe" },
});
gunsole.database.warn("Slow query detected", {
context: { query: "SELECT * FROM users", duration: 2300 },
});
gunsole.auth(message: string, options?: BucketLogOptions): void
gunsole.auth.info(message: string, options?: BucketLogOptions): void
gunsole.auth.debug(message: string, options?: BucketLogOptions): void
gunsole.auth.warn(message: string, options?: BucketLogOptions): void
gunsole.auth.error(message: string, options?: BucketLogOptions): void
gunsole.auth.fatal(message: string, options?: BucketLogOptions): void

BucketLogOptions is LogOptions without bucket and message (both are positional/implied):

{
context?: Record<string, unknown>;
tags?: Partial<Tags> | TagEntry<Tags>[];
traceId?: string;
}

So when you call gunsole.payments("Checkout completed", { tags: ... }), it’s equivalent to:

gunsole.info({
bucket: "payments",
message: "Checkout completed",
tags: { ... },
});

The log() API still works with any bucket string. Bucket accessors are the typed surface; log() is the untyped escape hatch.

// Typed — autocomplete + compile-time check
gunsole.payments("User paid");
// Untyped — any bucket string accepted
gunsole.log({ bucket: "payments", message: "User paid" });
gunsole.log({ bucket: "some-dynamic-bucket", message: "..." });

Bucket names that conflict with GunsoleClient methods are rejected at both compile time and runtime:

log, info, debug, warn, error, fatal,
setUser, setSessionId, setDebug, flush, destroy, isDestroyed,
drainBatch, projectId, apiKey, logEndpoint,
attachGlobalErrorHandlers, detachGlobalErrorHandlers
// Compile-time error
const gunsole = createGunsoleClient({
projectId: "my-app",
mode: "local",
buckets: ["auth", "log"] as const,
// ^^^^^ ❌ Type error: "log" is a reserved bucket name
});

Omitting buckets returns a plain GunsoleClient — no phantom properties, no behavior change.

// No buckets — returns GunsoleClient<Tags> (clean type, no index signature)
const gunsole = createGunsoleClient({
projectId: "my-app",
mode: "local",
});
// No bucket accessors — must specify bucket in every call
gunsole.info({ bucket: "auth", message: "User logged in" });
gunsole.error({ bucket: "payments", message: "Charge failed" });
ExportDescription
BucketLogOptionsLog options for bucket methods (no bucket/message)
BucketLoggerCallable bucket accessor interface
WithBucketsMapped type adding bucket accessors to client
ReservedBucketNameUnion of reserved bucket names
ValidateBucketsCompile-time bucket name validator