Safe real-time utility toolkit for shnwazdev projects, published with GitHub Packages.
Use this package when you need small, dependency-free helpers for live app state, event messages, API polling, bot status checks, retries, timeouts, fast UI input control, and safe logging that avoids leaking tokens or private data.
- Package: https://github.com/shnwazdeveloper/shnwazdev-package/pkgs/npm/shnwazdev
- Repository: https://github.com/shnwazdeveloper/shnwazdev-package
- Owner:
shnwazdeveloper - Package name:
@shnwazdeveloper/shnwazdev - Registry:
https://npm.pkg.github.com
GitHub Packages does not use the normal public npm registry for this scoped package. Add this line to your user or project .npmrc:
@shnwazdeveloper:registry=https://npm.pkg.github.comIf the package is installed on your own machine, connect npm to your GitHub token:
gh auth refresh -h github.com -s read:packages
$token = gh auth token
npm config set "//npm.pkg.github.com/:_authToken" "$token" --location=userThen install:
npm install @shnwazdeveloper/shnwazdev@0.4.0createEventBusfor app events and message passingcreateRealtimeStorefor live state with subscriptions and selectorscreatePollerfor APIs, bots, dashboards, and workerscreateHeartbeatfor live status checkssleepfor async delaystimeoutfor stopping slow promisesretryfor retrying unstable operationsdebouncefor search boxes, resize handlers, and input eventsthrottlefor scroll, mousemove, and high-frequency eventsredactSensitiveDatafor removing passwords, tokens, cookies, and keysdetectSecretsfor finding sensitive values without printing raw secretsassertNoSecretsfor failing fast when a payload contains sensitive datasafeJsonStringifyfor circular-safe, redacted JSON outputcreateSafeLoggerfor console-style logging with automatic redactionmaskSecretfor safe secret previewscreateSecureIdfor crypto-safe request IDs and trace IDsconstantTimeEqualfor safer token/signature comparisonssanitizeHeadersfor redacted header logssanitizeUrlfor redacted URL logscreateRateLimiterfor local abuse protectioncreateCircuitBreakerfor failing safely when a dependency is unhealthysafeFetchfor timeout-aware, origin-guarded fetch calls with safe request logs
import {
createEventBus,
createPoller,
createRateLimiter,
createRealtimeStore,
createSafeLogger,
retry,
safeFetch,
timeout
} from "@shnwazdeveloper/shnwazdev";
const store = createRealtimeStore({ online: false, users: 0 });
store.subscribe((state) => {
console.log("state changed", state);
});
store.setState({ online: true });
const bus = createEventBus();
bus.on("message", (message) => console.log(message.text));
bus.emit("message", { text: "Hello from shnwazdev" });
const poller = createPoller(
async () => {
const response = await fetch("https://api.github.com");
return response.status;
},
{ interval: 5000 }
);
poller.onData((status) => console.log("GitHub status", status));
poller.start();
const response = await retry(
() => timeout(fetch("https://api.github.com"), 3000),
{ retries: 2, delay: 500 }
);
console.log(response.status);
const logger = createSafeLogger(console);
logger.log("safe output", {
username: "shnwazdeveloper",
token: "example-token-that-will-be-redacted"
});
const limiter = createRateLimiter({ limit: 10, interval: 60000 });
limiter.assert("user:shnwazdeveloper");
const { status, safeRequest } = await safeFetch("https://api.github.com", {
allowedOrigins: ["https://api.github.com"],
timeout: 3000
});
logger.info("request finished", { status, safeRequest });Use createRealtimeStore when several parts of an app need to react to shared state.
import { createRealtimeStore } from "@shnwazdeveloper/shnwazdev";
const store = createRealtimeStore({ connected: false, count: 0 });
const unsubscribe = store.subscribe((nextState, previousState) => {
console.log({ nextState, previousState });
});
store.select(
(state) => state.count,
(count) => console.log("count changed", count)
);
store.setState({ connected: true });
store.update((state) => ({ count: state.count + 1 }));
await store.waitFor((state) => state.count >= 1, { timeout: 1000 });
unsubscribe();Use createEventBus for local publish/subscribe events.
import { createEventBus } from "@shnwazdeveloper/shnwazdev";
const bus = createEventBus();
const off = bus.on("user:joined", (user) => {
console.log(`${user.name} joined`);
});
bus.once("ready", () => {
console.log("ready only runs one time");
});
bus.emit("user:joined", { name: "Shnwaz" });
bus.emit("ready");
off();Use createPoller to repeatedly run async work.
import { createPoller } from "@shnwazdeveloper/shnwazdev";
const poller = createPoller(
async ({ runCount }) => {
const response = await fetch("https://api.github.com");
return {
runCount,
ok: response.ok,
status: response.status
};
},
{
interval: 5000,
backoff: 2,
maxInterval: 30000
}
);
poller.onData((data) => console.log("data", data));
poller.onError((error) => console.error("poll failed", error));
poller.start();
const firstOk = await poller.until((data) => data.ok, { timeout: 20000 });
console.log(firstOk);
poller.stop();Use createHeartbeat when you want a small live signal for a bot, dashboard, worker, or connection monitor.
import { createHeartbeat } from "@shnwazdeveloper/shnwazdev";
const heartbeat = createHeartbeat({ interval: 1000 });
heartbeat.onBeat((beat) => {
console.log(`beat ${beat.count}`, beat.lastBeatAt);
});
heartbeat.start();
setTimeout(() => {
heartbeat.stop();
}, 5000);import {
debounce,
retry,
sleep,
throttle,
timeout
} from "@shnwazdeveloper/shnwazdev";
await sleep(500);
await timeout(fetch("https://api.github.com"), 3000);
await retry(
async () => {
const response = await fetch("https://api.github.com");
if (!response.ok) {
throw new Error("GitHub request failed");
}
return response;
},
{ retries: 3, delay: 500, factor: 2 }
);
const onSearch = debounce((query) => {
console.log("search", query);
}, 300);
const onScroll = throttle(() => {
console.log("scroll event");
}, 100);Use these helpers before logging API responses, request headers, environment snapshots, bot session data, or errors. They are designed to keep useful structure while removing sensitive values.
import { redactSensitiveData } from "@shnwazdeveloper/shnwazdev";
const safePayload = redactSensitiveData({
username: "shnwazdeveloper",
password: "my-password",
headers: {
authorization: "Bearer real-token-value"
}
});
console.log(safePayload);Output:
{
username: "shnwazdeveloper",
password: "[REDACTED]",
headers: {
authorization: "[REDACTED]"
}
}import { detectSecrets } from "@shnwazdeveloper/shnwazdev";
const findings = detectSecrets({
apiKey: "real-api-key-value",
message: "Bearer real-token-value"
});
console.log(findings);Findings include the path, type, and a masked preview. Raw secret values are not returned.
import { assertNoSecrets } from "@shnwazdeveloper/shnwazdev";
assertNoSecrets({
public: "safe",
token: "private-token"
});If sensitive data is found, this throws a SensitiveDataError.
import { safeJsonStringify } from "@shnwazdeveloper/shnwazdev";
const payload = { token: "private-token" };
payload.self = payload;
console.log(safeJsonStringify(payload));This handles circular objects and redacts sensitive values.
import { createSafeLogger } from "@shnwazdeveloper/shnwazdev";
const logger = createSafeLogger(console);
logger.info("request", {
user: "shnwazdeveloper",
cookie: "private-cookie",
token: "private-token"
});The logger keeps normal fields and replaces sensitive fields with [REDACTED].
import {
constantTimeEqual,
createSecureId
} from "@shnwazdeveloper/shnwazdev";
const requestId = createSecureId({ prefix: "req_", size: 16 });
console.log(requestId);
if (constantTimeEqual(userInputToken, expectedToken)) {
console.log("token matched");
}createSecureId uses crypto-safe random bytes. constantTimeEqual compares strings without returning early on the first different character.
import {
sanitizeHeaders,
sanitizeUrl
} from "@shnwazdeveloper/shnwazdev";
console.log(sanitizeUrl("https://example.com/search?q=node&token=private"));
console.log(sanitizeHeaders({
authorization: "Bearer private",
accept: "application/json"
}));This keeps useful debugging details while removing sensitive values.
Use createRateLimiter to protect local commands, bots, API handlers, and expensive tasks from repeated calls.
import { createRateLimiter } from "@shnwazdeveloper/shnwazdev";
const limiter = createRateLimiter({
limit: 5,
interval: 60000
});
try {
limiter.assert("user:shnwazdeveloper");
console.log("allowed");
} catch (error) {
console.log(error.name, error.retryAfter);
}Use createCircuitBreaker around unstable downstream work. After too many failures, it opens and stops calling the failing task until the recovery time passes.
import { createCircuitBreaker } from "@shnwazdeveloper/shnwazdev";
const breaker = createCircuitBreaker(
async () => {
const response = await fetch("https://api.github.com");
if (!response.ok) {
throw new Error("GitHub request failed");
}
return response;
},
{
failureThreshold: 3,
recoveryTime: 30000
}
);
const response = await breaker.execute();
console.log(response.status);Use safeFetch when you want origin checks, timeouts, and safe request metadata for logs.
import { safeFetch } from "@shnwazdeveloper/shnwazdev";
const result = await safeFetch("https://api.github.com", {
allowedOrigins: ["https://api.github.com"],
timeout: 3000,
init: {
headers: {
authorization: "Bearer private",
accept: "application/json"
}
}
});
console.log(result.status);
console.log(result.safeRequest);safeRequest contains a sanitized URL and sanitized headers, so you can log it without exposing private data.
Clone the repository:
git clone https://github.com/shnwazdeveloper/shnwazdev-package.git
cd shnwazdev-packageRun tests:
npm testCheck for accidental secrets:
npm run secret:checkCheck what files will be published:
npm run pack:checkRun every safety check before publishing:
npm run safe:checkGitHub Actions publishes this package automatically when a version tag is pushed.
- Edit the code or README.
- Update
versioninpackage.json. - Run checks:
npm test
npm run secret:check
npm run pack:check- Commit and push:
git add .
git commit -m "Update package"
git push origin main- Create and push a version tag:
git tag v0.4.0
git push origin v0.4.0After the tag is pushed, the Publish Package GitHub Actions workflow runs and publishes the new version to GitHub Packages.
.envand.env.*are ignored by git.npm run secret:checkscans source/docs for common leaked token patterns.npm run safe:checkruns secret scanning, tests, and package dry-run together.- The CI workflow runs
safe:checkon pushes and pull requests. - The publish workflow runs secret scanning and tests before
npm publish. - Runtime helpers redact sensitive keys like
password,token,secret,apiKey,authorization,cookie, andprivateKey. - Detection results only show masked previews, not raw secret values.
safeFetchcan restrict calls to allowed origins and returns redacted request metadata for logs.createRateLimiterandcreateCircuitBreakerhelp reduce repeated abuse and unsafe retry storms.
This means npm is looking in the wrong registry.
Fix:
npm config set "@shnwazdeveloper:registry" "https://npm.pkg.github.com" --location=userThis means npm is using GitHub Packages but does not have a token.
Fix:
gh auth refresh -h github.com -s read:packages
$token = gh auth token
npm config set "//npm.pkg.github.com/:_authToken" "$token" --location=userGitHub Packages does not let the same package version be published twice. Increase the version in package.json, then push a matching new tag.
MIT