npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@freshpointcz/fresh-core

v0.0.24

Published

Contains core mechanisms for our custom framework

Readme

@freshpointcz/fresh-core

Core framework mechanisms shared by every FreshPoint microservice — base TypeORM entities, a DAO base class, typed HTTP errors, pagination helpers, a cron-job base class, and a grab-bag of type guards, date utilities, and shared enums.

This package is the foundation the other @freshpointcz/* packages and every service build on top of. It doesn't own any business domain — it only standardizes the plumbing (entities, errors, pagination, scheduling) so every service does it the same way.


Installation

npm install @freshpointcz/fresh-core

Requires Node.js ≥ 20. The package declares several peer dependencies — install whichever ones your service actually needs:

npm install typeorm typeorm-naming-strategies dayjs node-schedule
npm install -D eslint eslint-config-prettier eslint-plugin-prettier jiti prettier typescript-eslint

| Peer dependency | Needed for | | --- | --- | | typeorm | FreshEntity, FreshHyperEntity, FreshDao, subscribers, PgDataSourceOptions | | typeorm-naming-strategies | PgDataSourceOptions (snake_case column naming) | | dayjs | DateUtils, StatusDto | | node-schedule | FreshJob | | eslint, eslint-config-prettier, eslint-plugin-prettier, jiti, prettier, typescript-eslint | freshEslintConfig |

TypeScript decorators must be enabled (experimentalDecorators + emitDecoratorMetadata) since TypeORM entities rely on them — see tsconfig.base.json at the repo root.


Module map

src/
├── core/         FreshJob (cron), DataHelper, FreshError + HTTP error subclasses, BusinessWarning
├── database/     FreshEntity / FreshHyperEntity / FreshTranslationBase, FreshDao, @TimestampColumn, BaseEntityChangeSubscriber
├── common/       Pagination, typeguards, date utils, Singleton, Deferred, StatusDto, amount units
├── config/       freshEslintConfig, PgDataSourceOptions (starter TypeORM config)
├── enums/        HttpStatus, LanguageCode, TransactionType, PaymentMethod, DepotPoolStatus, ActionCommandCode
├── interfaces/   HealthCheckResult
└── types/        Maybe<T>, Status, CardNumber

Everything is re-exported from the package root, so import { FreshEntity, HttpStatus, getPaginationParams } from "@freshpointcz/fresh-core" works regardless of which submodule it actually lives in.


Errors

FreshError — base HTTP error

FreshError carries a status code, a machine-readable Status string, and an optional detail message. error.name is set to the concrete subclass name, so logs and stack traces read NotFoundError instead of Error.

import { NotFoundError, HttpStatus } from "@freshpointcz/fresh-core";

throw new NotFoundError("Product 42 does not exist");

// preserve the original error for logging
try {
    await db.findUser(id);
} catch (err) {
    throw new InternalServerError("DB query failed", { cause: err });
}

Every subclass hardcodes its HTTP status code and Status string — construct the one matching your case instead of the base FreshError:

| Class | Status code | Status | | --- | --- | --- | | BadRequestError | 400 | validation-error | | UnauthorizedError | 401 | not-authenticated | | PaymentRequiredError | 402 | error | | ForbiddenError | 403 | not-authorized | | NotFoundError | 404 | error | | MethodNotAllowedError | 405 | error | | NotAcceptableError | 406 | error | | ProxyAuthenticationRequiredError | 407 | not-authenticated | | RequestTimeoutError | 408 | error | | ConflictError | 409 | error | | GoneError | 410 | error | | LengthRequiredError | 411 | error | | PreconditionFailedError | 412 | error | | PayloadTooLargeError | 413 | error | | UriTooLongError | 414 | error | | UnsupportedMediaTypeError | 415 | error | | RangeNotSatisfiableError | 416 | error | | ExpectationFailedError | 417 | error | | ImATeapotError | 418 | error | | MisdirectedRequestError | 421 | error | | UnprocessableEntityError | 422 | validation-error | | LockedError | 423 | error | | FailedDependencyError | 424 | error | | TooEarlyError | 425 | error | | UpgradeRequiredError | 426 | error | | PreconditionRequiredError | 428 | error | | TooManyRequestsError | 429 | error | | RequestHeaderFieldsTooLargeError | 431 | error | | UnavailableForLegalReasonsError | 451 | error | | InternalServerError | 500 | internal-server-error | | NotImplementedError | 501 | internal-server-error | | BadGatewayError | 502 | internal-server-error | | ServiceUnavailableError | 503 | internal-server-error | | GatewayTimeoutError | 504 | internal-server-error | | HttpVersionNotSupportedError | 505 | internal-server-error | | VariantAlsoNegotiatesError | 506 | internal-server-error | | InsufficientStorageError | 507 | internal-server-error | | LoopDetectedError | 508 | internal-server-error | | NotExtendedError | 510 | internal-server-error | | NetworkAuthenticationRequiredError | 511 | internal-server-error |

Each error exposes statusCode and statusDto (a StatusDto built from the status + detail), ready to send straight back to the client from an error-handling middleware.

ApiError still exists but is deprecated — use FreshError (or a subclass) instead.

BusinessWarning

For non-fatal business-rule violations that should reach the caller without being treated as a system error (no HTTP status attached):

import { BusinessWarning } from "@freshpointcz/fresh-core";

throw new BusinessWarning("ORDER_ALREADY_SENT", "Tato objednávka již byla odeslána.");

Database

Base entities

| Class | Use for | Adds | | --- | --- | --- | | FreshEntity | Regular tables | id (auto-increment PK), uuid (unique, gen_random_uuid()), created_at, updated_at, deleted_at (soft delete) | | FreshHyperEntity | TimescaleDB hypertables | timestamp (primary key), created_at | | FreshTranslationBase<T> | i18n side-tables | id, languageCode (checked against LanguageCode), abstract baseEntity: T |

import { Entity, Column } from "typeorm";
import { FreshEntity } from "@freshpointcz/fresh-core";

@Entity()
export class Product extends FreshEntity {
    @Column()
    name: string;
}

FreshHyperEntity expects the table to actually be converted to a hypertable in a migration:

// up
await queryRunner.query(`SELECT create_hypertable('my_hyper_table', 'timestamp', if_not_exists => TRUE);`);
// down
await queryRunner.query(`SELECT drop_hypertable('my_hyper_table', if_exists => TRUE);`);

FreshTranslationBase requires the concrete relation to be added by the subclass:

@Entity()
export class ProductTranslation extends FreshTranslationBase<Product> {
    @ManyToOne(() => Product, { onDelete: "CASCADE" })
    baseEntity: Product;
}

@TimestampColumn()

A @Column preset for timestamptz columns defaulting to CURRENT_TIMESTAMP — used internally by FreshHyperEntity.created_at, and available for any other "inserted at" column.

class Delivery extends FreshHyperEntity {
    @TimestampColumn({ nullable: true })
    confirmedAt: Date | null;
}

FreshDao<T>

Thin abstract base for DAO classes. Supplies getRepo(), which returns the injected repository or, when a transactional EntityManager is passed in, the repository scoped to that transaction.

import { FreshDao } from "@freshpointcz/fresh-core";
import { Repository, EntityManager } from "typeorm";
import { Product } from "./product.entity";

export class ProductDao extends FreshDao<Product> {
    protected repo = Product.getRepository ? undefined! : (undefined as any); // wire up your own repo injection
    protected entity = Product;

    async findOne(id: number, manager?: EntityManager) {
        return this.getRepo(manager).findOneBy({ id });
    }
}

BaseEntityChangeSubscriber<Entity, IdType>

Abstract TypeORM EntitySubscriberInterface base that batches insert/update/soft-remove events per transaction and fires a single notification per entity after commit — so a row updated three times in one transaction only notifies once (created wins over everything, deleted wins over updated).

import { EntityManager } from "typeorm";
import { BaseEntityChangeSubscriber, EntityChangeEvent } from "@freshpointcz/fresh-core";
import { Product } from "./product.entity";

export class ProductChangeSubscriber extends BaseEntityChangeSubscriber<Product> {
    protected readonly PENDING_KEY = "product-change-subscriber";
    protected readonly SUBSCRIBER_NAME = "ProductChangeSubscriber";

    listenTo() {
        return Product;
    }

    protected async handleNotification(
        id: number,
        changeEvent: EntityChangeEvent,
        manager: EntityManager
    ): Promise<void> {
        await Messenger.publisher.publish(`product.${changeEvent}`, { id });
    }
}

If a write happens outside an active transaction, the notification fires immediately and a warning is logged (Notification sent outside transaction for id=...) — subscribers are meant to run inside transactional writes.


Pagination

Offset-based pagination helpers shared across DAO, service, and controller layers — PaginationParams, PaginationMeta, PaginatedList<T>, getPaginationParams, constructTypeormPagination, getPaginationMeta, parsePaginationFromURL, listAll, plus find-options builders (buildDateRange, buildOrder, buildPagination).

import {
    getPaginationParams,
    constructTypeormPagination,
    getPaginationMeta,
    PaginatedList,
} from "@freshpointcz/fresh-core";

async function findMany(options: { pagination?: Partial<PaginationParams> }): Promise<PaginatedList<Product>> {
    const pagination = getPaginationParams(options.pagination); // → { page, limit, skip }

    const [data, total] = await repo.findAndCount({
        ...constructTypeormPagination(pagination), // → { take, skip }
    });

    return { data, meta: getPaginationMeta(total, pagination.page, pagination.limit) };
}

For the full walkthrough (controller → service → DAO → response), default values, and listAll for bulk/background jobs, see src/common/pagination/README.md.


Scheduled jobs — FreshJob<TResponse, TParams>

Abstract base class for cron-scheduled singletons, built on node-schedule. Each subclass:

  • exists exactly once per process (extends the internal Singleton pattern),
  • validates its cron expression at construction time (fails loudly on invalid cron),
  • always runs in the Europe/Prague timezone,
  • exposes a single invoke(input) entry point — called by the cron trigger with defaultInput, or directly by external callers with any compatible input.
import { FreshJob } from "@freshpointcz/fresh-core";

class NightlyCreditResetJob extends FreshJob<void, { dryRun: boolean }> {
    private static _instance: NightlyCreditResetJob;
    static getInstance() {
        return (this._instance ??= new NightlyCreditResetJob());
    }

    private constructor() {
        super("nightly-credit-reset", "0 3 * * *", true, { dryRun: false });
    }

    async invoke(input: { dryRun: boolean }): Promise<void> {
        // business logic here
    }
}

NightlyCreditResetJob.getInstance();

Do not override the constructor beyond calling super(...) — all business logic belongs in invoke. Use reschedule(newCron) to change the cron expression at runtime, and the protected defaultInput setter to change what the next scheduled tick receives.


DataHelper<T>

Abstract base for lazily-loaded, memoized data with request de-duplication: calling getData() while a load is already in flight returns the same in-flight promise instead of triggering a second fetch.

import { DataHelper, Maybe } from "@freshpointcz/fresh-core";

class ActiveDeviceIdsHelper extends DataHelper<number[]> {
    async startDataRetrieval(): Promise<Maybe<number[]>> {
        return deviceDao.findActiveIds();
    }
}

const helper = new ActiveDeviceIdsHelper(true, Promise.resolve([]));
const ids = await helper.getData(); // fetches once; concurrent calls share the same promise

Common utilities

Singleton

Per-subclass singleton base class — each subclass of Singleton gets exactly one instance, tracked in an internal registry keyed by constructor. Subclasses must not override the constructor and must put initialization logic in onInit() instead. FreshJob is built on top of this.

Promise helpers

| Export | Purpose | | --- | --- | | createDeferred<T>() | Returns { promise, resolve, reject } — a promise you can resolve/reject from outside its executor. Useful as a placeholder before the real async operation is known. | | SinglePromiseWaiter<T> | Singleton holding at most one in-flight promise for a process-wide flow; the stored promise clears itself once it settles. |

const deferred = createDeferred<string>();
startExternalProcess((result) => deferred.resolve(result));
const result = await deferred.promise;

Date utilities — DateUtils

Static helper class wrapping dayjs (with utc, timezone, isBetween, customParseFormat plugins pre-loaded).

| Method | Description | | --- | --- | | DateUtils.HOLIDAYS_STR / DateUtils.HOLIDAYS | Czech public holidays 2025–2030, as ISO date strings / UTC epoch millis | | fromISOtoSQLtimestamp(ts?) | ISO string → "YYYY-MM-DD HH:mm:ss" (UTC) | | toSQLtimestamp(ts) / fromSQLtimestamp(str) | Dayjs ↔ SQL timestamp string | | getSqlTimestampFromNowCzech() | Current Czech time as a SQL timestamp string | | fromISO(isoDate) | Parses an ISO string as UTC | | getNow() / getNowCzech() | Current time (UTC) / current time in Europe/Prague, returned as UTC Dayjs | | getLastSunday(weeksOffset?) | Midnight of the most recent Sunday, optionally further back N weeks | | dayInWeek(ts?) | ISO weekday (Monday=1 … Sunday=7, unlike dayjs's native Sunday=0) | | isWorkdayDay(ts) | false for weekends and Czech public holidays | | getDiffInMinutesWithNow(ts) | Minutes between now and ts | | isInLastDays(numOfDays, ts) | Whether ts falls within the last N days |

Type guards

import {
    isObject, hasOwn,
    isNumber, isString, isFlag01, isNumberInRange, TO_BINARY_FLAG,
    isEnumValue,
    isDecimal, toDecimal,
    isMaybe,
} from "@freshpointcz/fresh-core";

| Function | Narrows to / returns | Notes | | --- | --- | --- | | isObject(v) | Record<string, unknown> | Non-null objects only (arrays/functions technically pass too) | | hasOwn(obj, key) | boolean | Safe wrapper around Object.prototype.hasOwnProperty | | isNumber(v) | number | Rejects NaN/Infinity | | isString(v) | string | | | isFlag01(v) | 0 \| 1 | | | isNumberInRange(v, min, max, opts?) | number | Inclusive by default; { includeMin, includeMax } to exclude bounds | | TO_BINARY_FLAG(v) | 0 \| 1 | Converts number \| boolean \| null \| undefined to a binary flag | | isEnumValue(enumObj, v) | E[keyof E] | Falls back to accepting any string \| number if enumObj is undefined | | isDecimal(v, options?) | number \| string | Validates finite decimals (number or string form); supports allowedType, decimalPoint (./,), precision, scale — see overloads for full narrowing behavior | | toDecimal(num, precision?, scale?) | string | Formats a number as a DB-safe decimal string; throws if it exceeds precision/scale (defaults 9,2) | | isMaybe(v, inner) | Maybe<T> | true for null or values satisfying innerdoes not accept undefined |

Other utils

| Function | Purpose | | --- | --- | | runWithConcurrency(items, concurrency, worker) | Runs an async worker over items with a bounded concurrency pool | | resolvePathParameterId(id) | tsoa path params are always strings — returns number if purely numeric, otherwise the original string (for numeric-ID-or-UUID routes) | | isValidCron(expr) | Structural validation of a 5–6 field numeric cron expression | | buildPatch(data, keys, transforms?) | Builds a partial patch object from a DTO, only including defined keys, with optional per-key transform functions |

const patch = buildPatch(updateDto, ["name", "active"] as const, {
    active: (v) => (v ? 1 : 0),
});

StatusDto / UserJwtDto

StatusDto is the structured { status, timestamp, details? } body attached to every FreshError (timestamp defaults to now in Europe/Prague, ISO-formatted). UserJwtDto describes the shape of a decoded user JWT (id, firstName, lastName, email, roles, iat?, exp?).

AMOUNT_UNIT

Lookup table for product amount units, keyed by numeric unit id, with symbol and Czech/English translations:

AMOUNT_UNIT[2]; // → { symbol: "kg", translations: { en: "kilogram", cs: "kilogram" } }

Schema

src/common/schema ships thin Category, Subcategory, Manufacturer, Device, and Product TypeORM entities (each just extends FreshEntity) plus COMMON_DATA_SOURCE — a ready-to-use Postgres DataSource pointed at the shared common schema, driven by POSTGRE_SQL_* env vars (HOST, PORT, USER, PASSWORD, DB, SCHEMA) and RUN_MIGRATIONS.

These are the canonical, shared reference entities (categories, manufacturers, devices, products) that multiple services read — extend them in your own service only if you need additional columns via a translation/side table.


Config

| Export | Description | | --- | --- | | freshEslintConfig | The workspace-wide ESLint flat config (Prettier integration, naming conventions, prefer-const, eqeqeq, etc.) — re-exported at the monorepo root's eslint.config.mts and consumable by any service | | PgDataSourceOptions | A starter TypeORM DataSourceOptions template for new services — snake_case naming strategy, UTC, POSTGRE_SQL_* env vars, migrations enabled via RUN_MIGRATIONS. Placeholder values (<service-name>, <host>, …) are meant to be adjusted per service. Call dotenv.config() before importing this. |

import { config } from "dotenv";
config();
import { PgDataSourceOptions } from "@freshpointcz/fresh-core";

Enums

| Enum | Values | | --- | --- | | HttpStatus | Full set of standard HTTP status codes (100–511) | | LanguageCode | CS, EN, DE, PL, SK | | TransactionType | WRITEOFF, SALE, LOST, ADD, DELIVERY, DEPOT_WRITEOFF, DEPOT_ADD, RETURN, INVENTORY_SURPLUS, INVENTORY_MISSING | | PaymentMethod | CODE, CARD, NONE, CREDIT | | DepotPoolStatus | NEW, PICKED, WRITTEN_OFF, ACTIVE, TERMINATED | | ActionCommandCode | RESTART_PC, RESTART_APPLICATION, RESTART_ROUTER, RESTART_REMOTE_CONTROL, SYNCHRONIZE, DIAGNOSE_LOCKS, SYNCHRONIZE_CONFIG |


Interfaces & types

| Export | Description | | --- | --- | | HealthCheckResult | Standard shape for service health checks — server: boolean, optional db (bool or per-driver breakdown), optional extras map for additional checked dependencies | | Maybe<T> | T \| null (see isMaybe above) | | Status | Union of the machine-readable statuses used by StatusDto/FreshError: "ok" \| "error" \| "not-authorized" \| "not-authenticated" \| "internal-server-error" \| "validation-error" | | CardNumber | Template-literal type for a 4-digit card number segment |


Project structure

src/
├── index.ts                              Public barrel — re-exports common, core, types, database, config, enums, interfaces
├── common/
│   ├── constants/amount-unit.ts          AMOUNT_UNIT lookup table
│   ├── date-utils.ts                     DateUtils (dayjs-based)
│   ├── dto/status-dto.ts, UserJwtDto.ts
│   ├── pagination/                       Pagination building blocks (own README)
│   ├── patterns/singleton.ts             Singleton base class
│   ├── promise-magic/                    createDeferred, SinglePromiseWaiter
│   ├── schema/                           Shared entities + COMMON_DATA_SOURCE
│   ├── typeguards/                       decimal, enums, objects, primitives guards
│   └── utils/                            async, patch, cron-validity, path-param resolver
├── core/
│   ├── class/fresh-job.ts                FreshJob
│   ├── data-helper.ts                    DataHelper
│   └── errors/                           FreshError + subclasses, BusinessWarning, deprecated ApiError
├── database/
│   ├── entities/                         FreshEntity, FreshHyperEntity, FreshTranslationBase
│   ├── decorators/timestamp-column.ts    @TimestampColumn
│   ├── dao/fresh-dao.ts                  FreshDao
│   └── subscribers/                      BaseEntityChangeSubscriber
├── config/                                freshEslintConfig, PgDataSourceOptions
├── enums/                                 HttpStatus, LanguageCode, TransactionType, PaymentMethod, DepotPoolStatus, ActionCommandCode
├── interfaces/healthcheck-result.ts
└── types/                                 Maybe, Status, CardNumber

License

ISC