JavaScript / TypeScript SDK
Install
Section titled “Install”pnpm add gunsole-jsWorks in browsers and Node.js 18+. Zero runtime dependencies.
Initialize
Section titled “Initialize”import { createGunsoleClient } from "gunsole-js";
const gun = createGunsoleClient({ projectId: "my-app", apiKey: "dev", mode: "local",});Config options
Section titled “Config options”| Option | Type | Default | Description |
|---|---|---|---|
projectId | string | required | Identifies your project in the desktop app |
apiKey | string | — | API key (required for cloud mode, any string for local) |
mode | "local" | "desktop" | "cloud" | required | Determines the endpoint URL |
endpoint | string | — | Override the endpoint URL entirely |
env | string | — | Environment label (e.g. "production", "staging") |
appName | string | — | Application name, attached to every log |
appVersion | string | — | Application version, attached to every log |
defaultTags | Record<string, string> | — | Tags merged into every log entry |
batchSize | number | 10 | Number of logs to collect before auto-flushing |
flushInterval | number | 5000 | Auto-flush interval in milliseconds |
fetch | FetchFunction | globalThis.fetch | Custom fetch implementation |
isDebug | boolean | false | Disables gzip compression for debugging |
buckets | string[] | — | Typed bucket accessors with autocomplete |
Modes and endpoints
Section titled “Modes and endpoints”| Mode | Endpoint |
|---|---|
local | http://localhost:17655 |
desktop | http://localhost:8787 |
cloud | https://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.
Logging
Section titled “Logging”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() accepts an optional level as the first argument:
gun.log({ bucket: "api", message: "Request handled" }); // defaults to "info"gun.log("error", { bucket: "api", message: "Something broke" }); // explicit levelLogOptions
Section titled “LogOptions”| Field | Type | Required | Description |
|---|---|---|---|
message | string | yes | The log message |
bucket | string | yes | Category/namespace for this log |
context | Record<string, unknown> | no | Arbitrary structured data |
tags | Record<string, string> | no | Key-value pairs for filtering (string values only) |
traceId | string | no | Links related logs across operations |
What gets sent
Section titled “What gets sent”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}User and session tracking
Section titled “User and session tracking”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", },});Default tags from 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" },});
// Sent tags: { service: "api-server", region: "us-east-1", route: "/users" }gun.info({ bucket: "api", message: "Request", tags: { route: "/users" } });For compile-time tag safety with TypeScript, see Typed Tags.
Batching and flushing
Section titled “Batching and flushing”Logs are buffered and sent in batches. A batch is flushed when:
- The batch reaches
batchSize(default: 10) - The
flushIntervaltimer fires (default: 5000ms) - You call
gun.flush()manually
await gun.flush();The SDK compresses payloads with gzip by default. Set isDebug: true to send plain JSON (useful for inspecting network requests).
Error handling
Section titled “Error handling”The SDK is built to never crash your app. All internal errors are silently caught. Failed HTTP requests are retried up to 3 times with exponential backoff (1s, 2s, 4s).
Global error handlers
Section titled “Global error handlers”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 to these buckets: global_error, unhandled_rejection, uncaught_exception.
gun.detachGlobalErrorHandlers();Cleanup
Section titled “Cleanup”When your app is shutting down (or a component unmounts):
gun.destroy();This flushes remaining logs, clears timers, and detaches global error handlers.
// ReactuseEffect(() => { const gun = createGunsoleClient({ ... }); return () => gun.destroy();}, []);Next steps
Section titled “Next steps”- Typed Buckets — first-class bucket accessors with autocomplete
- Tags — dynamic filters and compile-time tag safety
- Configuration Reference — every option in one place