Skip to content

JavaScript / TypeScript SDK

import { Aside, Tabs, TabItem } from ‘@astrojs/starlight/components’;

Terminal window
pnpm add gunsole-js

Works in browsers and Node.js. Zero runtime dependencies.

import { createGunsoleClient } from "gunsole-js";
const gun = createGunsoleClient({
projectId: "my-app",
apiKey: "dev",
mode: "local",
});
OptionTypeDefaultDescription
projectIdstringrequiredIdentifies your project in the desktop app
apiKeystringrequiredAPI key (use any string for local mode)
mode"local" | "desktop" | "cloud"requiredDetermines the endpoint URL
endpointstringOverride the endpoint URL entirely
envstringEnvironment label (e.g. "production", "staging")
appNamestringApplication name, attached to every log
appVersionstringApplication version, attached to every log
defaultTagsRecord<string, string>Tags merged into every log entry
batchSizenumber10Number of logs to collect before auto-flushing
flushIntervalnumber5000Auto-flush interval in milliseconds
fetchFetchFunctionglobalThis.fetchCustom fetch implementation
isDebugbooleanfalseDisables gzip compression for debugging
ModeEndpoint
localhttp://localhost:17655
desktophttp://localhost:8787
cloudhttps://api.gunsole.com

Use local during development with the desktop app. The endpoint option overrides the mode-based URL if you need a custom address.

Four methods, one for each level:

gun.info({ bucket: "api", message: "Request handled" });
gun.debug({ bucket: "api", message: "Cache miss", context: { key: "user:123" } });
gun.warn({ bucket: "api", message: "Slow query", context: { duration: 2500 } });
gun.error({ bucket: "api", message: "Connection refused", tags: { db: "postgres" } });

gun.log() is an alias for gun.info().

FieldTypeRequiredDescription
messagestringyesThe log message
bucketstringyesCategory/namespace for this log
contextRecord<string, unknown>noArbitrary structured data
tagsRecord<string, string>noKey-value pairs for filtering (string values only)
traceIdstringnoLinks related logs across operations

Each log entry is internally enriched before sending:

{
// from your call
bucket: "api",
message: "Request handled",
level: "info",
context: { ... },
tags: { ...defaultTags, ...yourTags }, // merged
// auto-populated
timestamp: 1708214400000, // Date.now()
userId: "u_123", // from setUser()
sessionId: "sess_abc", // from setSessionId()
env: "production", // from config
appName: "my-app", // from config
appVersion: "1.0.0", // from config
}
gun.setUser({
id: "u_123",
email: "ada@example.com",
name: "Ada Lovelace",
traits: {
plan: "pro",
team: "backend",
},
});
gun.setSessionId("sess_abc123");

Once set, userId and sessionId are attached to every subsequent log. Useful for filtering logs by user in the desktop app.

Tags are flat key-value pairs (string → string) that become dynamic filters in the desktop app.

gun.info({
bucket: "api",
message: "POST /users",
tags: {
route: "/users",
method: "POST",
status: "201",
},
});

In the desktop app, you’ll see three new filter dropdowns appear: route, method, and status. Each shows the values that have been seen. No schema, no config — just send the tags and the filters show up.

Tags from defaultTags in your config are merged with per-log tags. Per-log tags win on conflict.

const gun = createGunsoleClient({
projectId: "my-app",
apiKey: "dev",
mode: "local",
defaultTags: {
service: "api-server",
region: "us-east-1",
},
});
// This log gets: { service: "api-server", region: "us-east-1", route: "/users" }
gun.info({
bucket: "api",
message: "Request",
tags: { route: "/users" },
});

Logs are buffered and sent in batches. A batch is flushed when:

  • The batch reaches batchSize (default: 10)
  • The flushInterval timer fires (default: 5000ms)
  • You call gun.flush() manually
// Force send everything now
await gun.flush();

The SDK compresses payloads with gzip by default. Set isDebug: true to send plain JSON (useful for inspecting network requests).

The SDK is built to never crash your app. All internal errors are silently caught. In development (NODE_ENV === "development"), warnings are logged to the console.

Retry logic: failed HTTP requests are retried up to 3 times with exponential backoff (1s, 2s, 4s).

Automatically catch unhandled errors and promise rejections:

gun.attachGlobalErrorHandlers();

In the browser, this listens to window.addEventListener("error") and window.addEventListener("unhandledrejection").

In Node.js, this listens to process.on("uncaughtException") and process.on("unhandledRejection").

Captured errors are logged as error level in the global_errors bucket.

// Clean up when done
gun.detachGlobalErrorHandlers();

When your app is shutting down (or a component unmounts):

gun.destroy();

This flushes remaining logs, clears timers, and detaches global error handlers.

The SDK is fully typed. Key types:

import type {
GunsoleClientConfig,
GunsoleClient,
LogOptions,
LogLevel,
UserInfo,
ClientMode,
} from "gunsole-js";