Offline developer-mode activation for Bun and Node.js applications.
@trebired/dev-mode gives products a small local runtime for turning on a custom developer mode without calling any remote service. It supports two activation styles:
match, where one local value must match another local valuesigned, where a local activation payload is verified against shipped public key material
The package is intentionally narrow. It helps with offline activation and stable runtime checks. It does not try to be a licensing platform, a cloud gate, or a hidden anti-tamper system.
Runtime support: Bun 1+ and Node.js 18+.
npm install @trebired/dev-modeimport { createDevMode } from "@trebired/dev-mode";
const devMode = createDevMode({
mode: "match",
match: {
env: { env: "DEV_MODE_KEY" },
match: { file: ".dev-mode-key" },
},
});
const state = devMode.activate();
if (devMode.isEnabled()) {
console.log("developer mode active");
}
console.log(state);The instance API is intentionally small:
activate()isEnabled()isMatchMode()isSignedMode()state()
If you want a one-shot helper, use activateDevMode(options).
match mode is a local friction check. It is useful when you want a product to require two local values to line up before developer mode turns on.
import { createDevMode } from "@trebired/dev-mode";
const parsedEnvFile = {
DEV_MODE_KEY: "local-demo-key",
};
const devMode = createDevMode({
mode: "match",
match: {
env: { env: "DEV_MODE_KEY" },
match: { key: "DEV_MODE_KEY", object: parsedEnvFile },
},
});
const state = devMode.activate();Supported local sources for match.env and match.match:
- direct values such as
"local-demo-key" - environment objects through
{ env: "DEV_MODE_KEY" } - parsed records through
{ key: "DEV_MODE_KEY", object: parsedEnvFile } - local files through
{ file: "./dev-mode-key.txt" }
String values are normalized with trimming by default. Activation only succeeds when both normalized values are present and equal.
Important: match mode is not a security boundary. It is a friction mechanism.
signed mode is stronger than shared-secret matching because the shipped product only needs public key material. A private key can stay elsewhere and produce local activation envelopes ahead of time.
The package verifies an embedded activation envelope of this shape:
{
"payload": {
"subject": "local-developer-mode",
"issued_at": "2026-05-23T00:00:00.000Z",
"expires_at": "2026-06-01T00:00:00.000Z",
"device": "workstation-17",
"metadata": {
"issued_by": "local-admin"
}
},
"signature": "<base64-ed25519-signature>"
}Runtime verification is local only:
import { createDevMode } from "@trebired/dev-mode";
const devMode = createDevMode({
mode: "signed",
signed: {
activation: { file: "./activation.json" },
publicKey: { file: "./keys/dev-mode-public.pem" },
},
});
const state = devMode.activate();If you want a local signing script elsewhere, sign the deterministic payload serialization that this package exports:
import fs from "node:fs";
import { sign } from "node:crypto";
import { serializeSignedPayload } from "@trebired/dev-mode";
const privateKey = fs.readFileSync("./keys/dev-mode-private.pem", "utf8");
const payload = {
subject: "local-developer-mode",
issued_at: "2026-05-23T00:00:00.000Z",
expires_at: "2026-06-01T00:00:00.000Z",
device: "workstation-17",
};
const signature = sign(
null,
Buffer.from(serializeSignedPayload(payload)),
privateKey,
).toString("base64");
fs.writeFileSync("./activation.json", JSON.stringify({
payload,
signature,
}, null, 2));Signed mode supports activation input from:
- direct activation objects
- local JSON strings
- local JSON files
The public key can come from:
- a PEM string
- a
KeyObject - a local PEM file
By default, successful activation sets NODE_ENV to "development".
The override policy is controlled with overrideNodeEnv:
"always": always setNODE_ENV="development"on successful activation"when-unset": only set it whenNODE_ENVis missing or blank"never": never modifyNODE_ENV
The state snapshot always includes:
activemodenode_env_overriddenoverride_node_envreason
Mode-specific flags are added when relevant, including:
env_key_presentmatch_key_presentpayload_presentsignature_presentpublic_key_presentexpires_atexpired
- an offline developer-mode activation helper
- a small runtime state wrapper around local activation checks
- a way to use public-key verification instead of shipping a shared secret
- not DRM
- not a remote licensing platform
- not a perfect anti-tamper system
- not a replacement for host-owned permissions, trust boundaries, or server-side enforcement
match mode is intentionally simple. If a user can inspect local files or environment values, they can usually reproduce the matching value. That is expected.
signed mode is stronger because the shipped product only needs a public key and verifies signatures locally. It avoids embedding a reusable shared secret in the product. Even so, if code runs on a user-controlled machine, the code and checks can still be patched, bypassed, or instrumented.
In plain terms:
matchmode is friction, not securitysignedmode is stronger, but still not absolute tamper resistance- this package is for offline mode gating and developer-mode control
- this package is not a perfect anti-tamper system
The first public slice is intentionally small:
createDevMode()activateDevMode()serializeSignedPayload()DevModeError
The package also exports the public TypeScript types for mode options, runtime state, logger hooks, and signed activation payloads.