Docs
Express
A shared client, a req.audit() helper so route code stays one-line, a feed-token endpoint, and clean shutdown.
1. Install and initialize
npm install @softechlog/node, set SOFTECHLOG_SECRET_KEY in your environment, and export one instance:
lib/softechlog.jsNode SDK
// lib/softechlog.js
const { Softechlog } = require('@softechlog/node');
const log = new Softechlog({
secretKey: process.env.SOFTECHLOG_SECRET_KEY, // stl_sk_…
});
module.exports = { log };2. A one-line audit helper
The actor is almost always req.user, so scope it once in middleware and keep route code to a single line:
middleware/audit.jsmiddleware
// middleware/audit.js — attach a pre-scoped helper per request
const { log } = require('../lib/softechlog');
function audit(req, res, next) {
req.audit = (action, target, metadata) =>
log.track({
actor: req.user
? { id: req.user.id, name: req.user.name, email: req.user.email }
: { id: 'anonymous' },
action,
target,
metadata,
});
next();
}
module.exports = { audit };routes/members.jsusage
// routes/members.js
const router = require('express').Router();
router.post('/workspaces/:id/members', async (req, res) => {
const invitee = await inviteMember(req.params.id, req.body);
req.audit('workspace.member.invited',
{ type: 'workspace', id: req.params.id },
{ invited_email: invitee.email, role: invitee.role });
res.status(201).json(invitee);
});track() never throws and retries transient failures internally — a logging outage can't take a request down, so there's no try/catch to write.
3. Feed token endpoint
routes/activity.jsserver
// routes/activity.js — feed token for the signed-in user
const { log } = require('../lib/softechlog');
router.get('/activity-token', requireAuth, async (req, res, next) => {
try {
const { token, expires_at } = await log.feedToken({
actorId: req.user.id,
ttlSeconds: 3600,
});
res.json({ token, expires_at });
} catch (err) {
next(err); // feedToken throws on failure — a missing token is a real error
}
});The browser exchanges nothing but this token — see the Feed Component guide for the front-end half.
4. Graceful shutdown
Long-running servers rarely need this, but draining on SIGTERM guarantees no events are lost during deploys:
server.jsflush on SIGTERM
// server.js — drain in-flight events on shutdown
process.on('SIGTERM', async () => {
await log.flush();
server.close(() => process.exit(0));
});