@polargold/pg-frontend-core
    Preparing search index...

    @polargold/pg-frontend-core

    pg-frontend-core

    Framework-agnostic utility classes, error types, and an Axios client factory shared across polargold's frontend apps.



    Beschreibung

    Prerequisites

    Getting started

    Useful commands

    Useful links

    Advanced topics



    Framework-agnostic (no Vue) TypeScript utility library for polargold frontend apps: date/currency formatting, a namespaced localStorage wrapper, an Axios client factory, an OIDC auth wrapper, Sentry config resolution, and typed error classes.

    Extracted from the near-duplicate composables/utilities found across luv-ui-tools, bws-ui-tools, and four app repos (luv-autoq-frontend, ama-deep, data-sheet-portal, bws-checkout-service-spa) during the September 2026 frontend tooling audit. Vue-specific composables built on top of this package live in the sibling @polargold/pg-frontend-vue package, not here — see What belongs here.


    • See NVM for installation.

    nvm use && npm install
    
    # Configure access to the polargold registry (once, globally). Token in Bitwarden under "[NPM Registry] pg-admin"
    npm config set -- //npm.white-lan.de/:_authToken=${token}
    cd your-project/

    echo "@polargold:registry=https://npm.white-lan.de" >> .npmrc
    npm install -S @polargold/pg-frontend-core

    Peer dependencies (installed automatically by npm ≥7, but listed explicitly since this is a library):

    {
    "axios": "^1.17.0",
    "dayjs": "^1.11.21"
    }

    npm run lint
    npm run lint:fix
    npm run vitest:run
    npm run vitest:coverage
    npm run docs:build
    npm run docs:serve
    npm run vite:build
    

    Service URL
    Package registry Package registry
    TypeDoc Not deployed yet — run npm run docs:serve locally. See the note in bitbucket-pipelines.yml.

    Framework-light, component-agnostic code only:

    • Static utility classes (src/utils)
    • A typed error hierarchy (src/errors)

    Anything that needs Vue (composables, anything using ref/computed/useRouter) belongs in @polargold/pg-frontend-vue, which depends on this package. Anything specific to one brand (colors, Tailwind config, useSeminarType, useHomeLink) belongs in that brand's own *-ui-library package, not here.

    Replaces the StorageHelper class duplicated in luv-autoq-frontend, ama-deep, data-sheet-portal, and bws-checkout-service-spa.

    Behavior change: the original StorageHelper.write() rejected every falsy value (if (!value) throw), which incorrectly rejected 0, false, and "". LocalStorage.write() only rejects undefined — check any code that relied on the old (buggy) rejection of falsy values when migrating.

    import { LocalStorage } from "@polargold/pg-frontend-core";
    import { version } from "../package.json";

    // Most keys: versioned, so stale state doesn't carry across a deploy.
    const filterStore = new LocalStorage("productSearchFilterParamsStore", {
    mode: import.meta.env.MODE,
    version,
    });

    // Access/session tokens: omit `version` so a deploy doesn't force everyone to
    // sign in again - matches luv-autoq-frontend's `new StorageHelper(StorageName.AccessToken, false)`.
    const accessTokenStore = new LocalStorage("accessToken", { mode: import.meta.env.MODE });

    accessTokenStore.write("some-token");
    accessTokenStore.read<string>(); // "some-token"
    accessTokenStore.remove();

    Replaces luv-ui-tools'/bws-ui-tools' DateFormatter (unchanged) — used internally by useDateTime in @polargold/pg-frontend-vue, or directly for non-Vue formatting needs.

    import { DateFormatter } from "@polargold/pg-frontend-core";

    DateFormatter.date(new Date()); // "04.09.26"
    DateFormatter.internationalDate(new Date()); // "2026-09-04"

    Replaces luv-ui-tools'/bws-ui-tools' CurrencyFormatter and bws-checkout-service-spa's standalone currencyHelper (constructor now takes optional currency/locale params, matching what currencyHelper already exposed).

    import { CurrencyFormatter } from "@polargold/pg-frontend-core";

    new CurrencyFormatter().formatCurrency(19.9); // "19,90 €"
    new CurrencyFormatter("USD", "en-US").formatCurrency(19.9); // "$19.90"

    Replaces luv-ui-tools'/bws-ui-tools' ColorGradient (brand-neutral ColorGradientDirectionName instead of a Luv/Bws-prefixed enum).

    import { ColorGradient, ColorGradientDirectionName } from "@polargold/pg-frontend-core";

    new ColorGradient().generate("#FFFFFF", "#000000", ColorGradientDirectionName.Vertical);

    Replaces the copies in luv-autoq-frontend and bws-checkout-service-spa. Ships with the regex fix luv-autoq-frontend already had (see the class's own doc comment) — bws-checkout-service-spa's copy was still affected by the bug this fixes.

    import { TypeCastUtils } from "@polargold/pg-frontend-core";

    new TypeCastUtils("42").typedValue; // 42
    new TypeCastUtils("true").typedValue; // true
    new TypeCastUtils("a,b,c").stringToArray; // ["a", "b", "c"]

    Replaces the identical copies in luv-autoq-frontend and bws-checkout-service-spa.

    import { removeWhiteSpace } from "@polargold/pg-frontend-core";

    removeWhiteSpace(" hello world "); // "helloworld"

    Replaces ama-deep's hand-rolled cleanseObject and bws-checkout-service-spa's removeEmptyProperties.

    import { cleanseObject } from "@polargold/pg-frontend-core";

    cleanseObject({ name: "x", note: "", count: 0, tags: [] }); // { name: "x", count: 0 }

    New — generalizes the near-identical axios.create() + interceptor blocks in luv-autoq-frontend's, ama-deep's and data-sheet-portal's api/modules/base files.

    import { createApiClient } from "@polargold/pg-frontend-core";
    import { accessTokenStore, appLanguageStore } from "./storage";
    import router from "@/router";
    import { ROUTE } from "@/router/routeDefinitions";

    export const apiClient = createApiClient({
    baseURL: import.meta.env.VITE_API_URL,
    getAccessToken: () => accessTokenStore.read<string>(),
    getAcceptLanguage: () => appLanguageStore.read<string>() ?? "en",
    onForbidden: () => router.push({ name: ROUTE.PUBLIC_PAGE_NOT_ALLOWED.NAME }),
    onServerError: () => router.push({ name: ROUTE.PUBLIC_ERROR_PAGE.NAME }),
    });

    A request can opt out of the forbidden handler with { suppressForbiddenRedirect: true } in its own Axios config — same escape hatch data-sheet-portal already relies on for downloads that handle a 403 locally.

    Replaces the copies in ama-deep and data-sheet-portal. Configuration is passed in explicitly (see the class's own doc comment for why), instead of being read from import.meta.env inside the class.

    import { AuthService } from "@polargold/pg-frontend-core";

    const authService = new AuthService({
    authority: import.meta.env.VITE_OPEN_ID_REALM_URL,
    clientId: import.meta.env.VITE_OPEN_ID_CLIENT_ID,
    redirectUri: import.meta.env.VITE_OPEN_ID_REDIRECT_URL,
    postLogoutRedirectUri: import.meta.env.VITE_OPEN_ID_POST_LOGOUT_REDIRECT_URL,
    });

    await authService.signInRedirect();

    Replaces the copies in luv-autoq-frontend, ama-deep and data-sheet-portal — but narrower on purpose. The source copies call @sentry/vue's Sentry.init({ app, ... }) with browserTracingIntegration({ router }), which needs a Vue App/Router — genuinely Vue-specific, so it doesn't belong in this framework-agnostic package. Here, InitializeSentry only resolves configuration (DSN gating, sample rates); a Vue app calls resolveConfig() and passes the result into @sentry/vue's own Sentry.init together with its own integrations (@polargold/pg-frontend-vue is expected to wrap this pattern).

    import { InitializeSentry } from "@polargold/pg-frontend-core";
    import * as Sentry from "@sentry/vue";
    import { version } from "../package.json";

    const sentry = new InitializeSentry({
    dsn: import.meta.env.VITE_SENTRY_DSN,
    environment: import.meta.env.VITE_SENTRY_ENVIRONMENT,
    release: version,
    validAppDomains: ["https://app.example.polargold.dev"],
    });

    const config = sentry.resolveConfig();

    if (config) {
    Sentry.init({
    app,
    ...config,
    integrations: [Sentry.browserTracingIntegration({ router }), Sentry.replayIntegration()],
    });
    }

    A non-Vue consumer can instead call sentry.initialize() directly for plain @sentry/browser error capture with no tracing integration.

    Ported unchanged from luv-ui-tools/bws-ui-tools. ApiCallError is thrown by API-calling wrappers such as @polargold/pg-frontend-vue's useApi; LocalStorageError (with a typed reason: "NO_KEY" | "NO_VALUE") is thrown by LocalStorage above.

    Every symbol is re-exported through its category's own index.ts (src/utils/index.ts, src/errors/index.ts) and through src/main.ts — nothing is auto-discovered. Follow this for anything new.

    Everything pushed as a tag is linted, tested, has its TypeDoc built, and is published to the internal package registry automatically — see bitbucket-pipelines.yml. Versioning itself is manual:

    npm version [major | minor | patch | x.x.x]
    
    Release type Description
    Major Breaking change to an exported class/function's public shape
    Minor A new exported utility
    Patch Bugfixes/improvements to existing utilities


    polargold GmbH, Lilienstraße 5-9 / Semperhaus C, 20095 Hamburg