Utilities

A reference for the built-in helper utilities Thunder ships under @/core/utils.

Thunder ships with a set of production-ready helpers under @/core/utils/. This page covers the standalone utilities. Some larger utilities have their own pages: createCRUD, Caching, Logger, and the Env class.


denoConfig

Provides access to your project's deno.json configuration at runtime - useful for reading project metadata, import maps, tasks, or custom config values.

denoConfig is an already-resolved object (loaded at module initialization), not a function. Do not call it.

import { denoConfig, readDenoConfig, denoConfigPath } from "@/core/utils/denoConfig.ts";

console.log(denoConfig.name);  // your project name
console.log(denoConfig.tasks); // configured deno tasks

// Read a different config file explicitly:
const other = await readDenoConfig("./plugins/foo/deno.json");

// Pass `true` as the second arg to read statically (JSON.parse, no import cache):
const fresh = await readDenoConfig(denoConfigPath, true);

Template Rendering

Render EJS or Handlebars templates to strings. Both functions take the template content as a string (not a file path) plus a data object. ejsRender is async; handlebarsRender is sync.

import { ejsRender, handlebarsRender } from "@/core/utils/textRender.ts";

const html = await ejsRender("<h1>Hello <%= name %></h1>", { name: "Alice" });

const greeting = handlebarsRender("Hello {{name}}", { name: "Bob" });

// To render a file, read it first:
const tpl = await Deno.readTextFile("templates/welcome.ejs");
const out = await ejsRender(tpl, { name: "Alice", appName: "Thunder App" });

return new Response(html, { headers: { "Content-Type": "text/html" } });

Hashing

One-way hashing built on Web Crypto (async) and Node crypto (sync). These produce digests only.

There is no verify helper - compare digests yourself. These are also not suitable for password storage on their own (no salting); use a dedicated KDF for passwords.

import {
  createHash,           // async, hex output
  createHashBase64,     // async, base64url output
  createHashSync,       // sync, hex output
  createHashBase64Sync, // sync, base64url output
  SupportedHashAlg,
} from "@/core/utils/hash.ts";

const hex     = await createHash(SupportedHashAlg.SHA_256, "data");
const b64     = await createHashBase64(SupportedHashAlg.SHA_256, "data");
const hexSync = createHashSync(SupportedHashAlg.SHA_256, "data");

// Manual verification:
const isMatch = (await createHash(SupportedHashAlg.SHA_256, input)) === stored;

Logger

A structured logging utility with colour-coded output for each severity level. Use Logger instead of console.log to maintain consistent, readable log output across your application.

import { Logger } from "@/core/utils/logger.ts";

Logger.success("Server started");
Logger.info("Connecting to database...");
Logger.warn("Rate limit approaching");
Logger.error("Failed to connect", error);
MethodUse Case
Logger.success(msg)Successful operations (e.g. startup, insert)
Logger.info(msg)General informational messages
Logger.warn(msg)Non-critical warnings
Logger.error(msg, err?)Errors and exceptions

Only errors are logged in production mode.


parseQueryParams

Parses a query string into a nested object via qs. It takes a string (not a Request).

import { parseQueryParams } from "@/core/utils/parseQueryParams.ts";

const params = parseQueryParams("?page=1&filter[status]=active");
// { page: "1", filter: { status: "active" } }

Inside route handlers, prefer queryAsJson(req) from @/core/http/utils.ts - it wraps parseQueryParams for requests and pairs naturally with Zod via $query.parse(queryAsJson(req)). See Routes.


paginated

Repeatedly invokes a callback in fixed-size pages until a page returns fewer items than limit (i.e. the last page). Useful for batch-processing an entire collection without loading it all into memory at once.

import { paginated } from "@/core/utils/paginate.ts";

await paginated(100, async (offset, limit) => {
  const batch = await collection.find().skip(offset).limit(limit).toArray();

  for (const doc of batch) {
    // process each doc...
  }

  return batch.length; // loop continues while this equals `limit`
});

See Also

These utilities also live under @/core/utils/ but have dedicated pages:


On this page