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

@believablecreations/bc-app-cms

v0.2.3

Published

Extensible application content management system for Angular

Downloads

780

Readme

@believablecreations/bc-app-cms

BC App CMS is a publishable Angular client and UI for an extensible application content management system.

The package is split into secondary entry points so applications only download a feature when its route or component is used:

  • @believablecreations/bc-app-cms — configuration, HTTP client, route composition
  • @believablecreations/bc-app-cms/api — CMS endpoint and access metadata maps
  • @believablecreations/bc-app-cms/pages — page models, APIs, forms, state, and page administration
  • @believablecreations/bc-app-cms/media — media models, API, NgRx state, uploads, screens, and routes
  • @believablecreations/bc-app-cms/blog — blog models, API, NgRx state, public/admin screens, and routes
  • @believablecreations/bc-app-cms/contact — contact models, API, state, form, admin screens, and routes
  • @believablecreations/bc-app-cms/config — application, API, security, SMS, and location APIs, NgRx state, and admin routes
  • @believablecreations/bc-app-cms/email — email models, APIs, NgRx state, administration screen, and routes
  • @believablecreations/bc-app-cms/access-control — permissions, roles, users, schemas, auth-cache APIs, NgRx state, and routes
  • @believablecreations/bc-app-cms/system — system import/export, audit, rollback, deferred-operation APIs/state, and routes
  • @believablecreations/bc-app-cms/users — user models, API, NgRx state, profile/admin screens, and routes
  • @believablecreations/bc-app-cms/notifications — notification APIs, realtime NgRx-style state, center, preferences, and routes
  • @believablecreations/bc-app-cms/store — commerce, checkout, orders, products, subscriptions, tax APIs, NgRx state, and routes
  • @believablecreations/bc-app-cms/shipping — shipping models, forms, APIs, NgRx state, and admin route
  • @believablecreations/bc-app-cms/square — Square catalog, media, order, subscription APIs, NgRx state, and admin route
  • @believablecreations/bc-app-cms/auth — auth APIs/forms, NgRx Signal Store, interceptor, adapters, screens, and routes
  • @believablecreations/bc-app-cms/media-config — media configuration, security incidents, and NgRx state
  • @believablecreations/bc-app-cms/routes — one-call routes for package-owned CMS screens
  • @believablecreations/bc-app-cms/shared — reusable controls such as the international phone input
  • @believablecreations/bc-app-cms/shell — reusable application shell, guards, realtime socket, consent, analytics, SEO, UI components, and shared application models

Install

npm install @believablecreations/bc-app-cms @ngrx/signals \
  @believablecreations/ngx-focus-point \
  @fortawesome/angular-fontawesome @fortawesome/free-brands-svg-icons

Angular, Angular Material/CDK, RxJS, NgRx Signals, Focus Point, and the public Font Awesome brand packages are peer dependencies. This keeps the consuming application in control of framework versions and prevents duplicate Angular or NgRx runtimes. Use Angular and NgRx versions whose peer ranges agree.

Use local library changes

The package includes the bc-app-cms-local command. For the first local setup in a consuming application, point it at the Believable Creations source workspace:

npx --no-install bc-app-cms-local \
  --source "/absolute/path/to/believable-creations-app"

The command builds BC App CMS and Focus Point, copies the completed builds to an immutable snapshot, and links both packages into the current application. Once the application is linked, rebuild and refresh the links with:

npx --no-install bc-app-cms-local

The immutable snapshot keeps a running consumer from observing ng-packagr while it is clearing and repopulating dist. To return to the versions declared in the consumer's package.json, run:

npx --no-install bc-app-cms-local --unlink

An application may add these commands as npm scripts, but it does not need its own linking or build helper.

Configure the client

import {provideHttpClient, withInterceptors} from '@angular/common/http';
import {provideBelievableCms} from '@believablecreations/bc-app-cms';
import {cmsAuthInterceptor, provideCmsAuthInterceptor} from '@believablecreations/bc-app-cms/auth';
import {provideCmsShell} from '@believablecreations/bc-app-cms/shell';

export const appConfig: ApplicationConfig = {
  providers: [
    provideBelievableCms({
      apiUrl: 'https://cms.example.com/api',
      adminPath: 'admin',
      defaultLanguage: 'en',
      branding: {
        appName: 'Example',
        logoUrl: '/assets/example-logo.svg',
        iconUrl: '/assets/example-icon.svg',
      },
      auth: {
        theme: 'centered-card',
      },
    }),
    provideCmsShell({
      baseUrl: 'https://www.example.com',
      socketUrl: 'https://cms.example.com',
      requireCookieConsentForGoogleAnalytics: true,
    }),
    provideCmsAuthInterceptor({
      accessToken: () => sessionStorage.getItem('access-token'),
      onTokenExpired: () => location.assign('/auth/sign-in'),
    }),
    provideHttpClient(withInterceptors([cmsAuthInterceptor])),
  ],
};

The auth interceptor only modifies requests under the configured CMS API URL. Realtime and notification side effects are exposed through optional adapters so the package can use the host application's socket, toast, and service-worker choices without importing host code.

User-facing package branding is read from the active AppConfig.appName value. Navigation labels, accessibility text, document titles, SEO, wallet labels, configuration defaults and email-template examples all use App when appName is missing, blank, or whitespace-only. The root entry point exports resolveCmsAppName() and DEFAULT_CMS_APP_NAME for host-owned UI that needs the same behavior.

Set branding.logoUrl and branding.iconUrl to host-owned image URLs. Auth renders the full logo on wider layouts and the compact icon on smaller screens. The legacy LOGO_CONFIG provider and direct app-logo logo/icon inputs remain supported and take precedence over the root branding defaults. The host is responsible for serving both assets.

Choose an authentication layout

Authentication themes are layout presets only. The package supplies the box structure and responsive behavior; the consuming application owns colors, typography, borders, imagery, and other visual treatment in global styles.

provideBelievableCms({
  apiUrl: 'https://cms.example.com/api',
  auth: {
    theme: 'split-panel',
    // `alternate` matches the supplied references: aside after sign-in,
    // aside before sign-up.
    splitPanelPosition: 'alternate',
  },
});

Available themes:

  • centered-card — brand above one centered form panel.
  • split-panel — supporting content and the form in two columns. Below 768px, the supporting panel collapses and the form's account-switch action remains available.

splitPanelPosition accepts start, end, or alternate. The exported CMS_AUTH_LAYOUT_THEMES constant and CmsAuthLayoutTheme type can drive a host configuration picker without duplicating the supported values.

The rendered layout exposes these stable global styling hooks:

  • bc-cms-auth-layout and .bc-cms-auth
  • .bc-cms-auth-scene, .bc-cms-auth-shell
  • .bc-cms-auth-brand, .bc-cms-auth-brand-content
  • .bc-cms-brand-logo, .bc-cms-brand-icon, and data-bc-cms-brand-asset
  • .bc-cms-auth-form, .bc-cms-auth-form-content
  • .bc-cms-auth-aside, .bc-cms-auth-aside-content
  • .bc-cms-auth-aside-brand, .bc-cms-auth-aside-title, .bc-cms-auth-aside-description, and .bc-cms-auth-aside-action
  • .bc-cms-auth-switch
  • data-bc-cms-auth-theme, data-bc-cms-auth-view, and data-bc-cms-auth-aside-position

Layout sizing can be tuned with --bc-cms-auth-scene-padding, --bc-cms-auth-scene-padding-mobile, --bc-cms-auth-shell-max-width, --bc-cms-auth-shell-max-width-mobile, --bc-cms-auth-shell-gap, --bc-cms-auth-split-gap, --bc-cms-auth-split-aside-width, --bc-cms-auth-split-form-width, --bc-cms-auth-aside-padding, and --bc-cms-auth-aside-action-min-width.

For example, a host can apply its design system without changing the selected structure:

bc-cms-auth-layout {
  --bc-cms-auth-shell-max-width: 68rem;
  --bc-cms-auth-aside-padding: 4rem;
}

.bc-cms-auth-scene {
  background: var(--app-auth-page-background);
  font-family: var(--app-body-font);
}

.bc-cms-auth-form-content,
.bc-cms-auth-aside-content {
  background: var(--app-auth-panel-background);
  color: var(--app-auth-panel-foreground);
}

CmsAuthLayoutComponent is also exported from @believablecreations/bc-app-cms/auth. A host-owned auth screen can pass its theme input directly; package-owned screens read the same value from provideBelievableCms().

Mount all package-owned screens

import {createBelievableCmsRoutes} from '@believablecreations/bc-app-cms/routes';

export const routes: Routes = [
  ...createBelievableCmsRoutes(),
];

The preset includes public auth/blog/contact/store screens, authenticated account and notification screens, and CMS administration for pages, users, access control, media, email, configuration, security, system, store, Square, and shipping. It returns final full-path route rows rather than guarded feature mounts. Public rows have no auth guard, customer-owned rows carry authGuard, and every administration row carries both authGuard and the exact API ACL action/resource guard required by that screen. Each feature can still be disabled with false or given a custom path, aliases, additional host guards, or a replacement lazy loader.

When the backend reports mustChangePassword, the auth guards redirect the session to /auth/change-password until the temporary password is replaced.

Mount one extracted feature

export const routes: Routes = [
  {
    path: 'admin/contact',
    loadChildren: () => import('@believablecreations/bc-app-cms/contact')
      .then(({CONTACT_ADMIN_ROUTES}) => CONTACT_ADMIN_ROUTES),
  },
];

Feature route arrays retain their own route-level guards when mounted separately.

The application mounts these package routes directly. CMS feature sources belong only in this package; consuming applications should not keep app-local copies or compatibility barrels.

Extend the right-panel menu

Host applications and separately installed feature libraries can contribute items without copying or modifying the package menu:

import {provideCmsMenuItems} from '@believablecreations/bc-app-cms/shell';

export const appConfig: ApplicationConfig = {
  providers: [
    provideCmsMenuItems(
      {
        // `root` is the right panel itself.
        targetId: 'root',
        audience: 'authenticated',
        placement: {after: 'shop'},
        items: [{
          id: 'appointments',
          icon: 'event',
          title: 'Appointments',
          link: '/appointments',
          params: {type: 'none'},
        }],
      },
      {
        // Any existing container ID can be targeted.
        targetId: 'administrator',
        audience: 'authenticated',
        placement: {before: 'settings'},
        items: ({permissions, userId}) => permissions.canReadAnyPage ? [{
          id: 'host-reports',
          icon: 'analytics',
          title: `Reports for ${userId}`,
          link: '/admin/reports',
          params: {type: 'none'},
        }] : [],
      },
    ),
  ],
};

Each call is a multi-provider, so multiple host features can register their own contributions independently. targetId can be root, administrator, store-management, or any other menu container ID. Placement supports start, end, {before: 'item-id'}, and {after: 'item-id'}. Item factories receive the current authentication state, user ID, store visibility, and package permission flags and are reevaluated with the right-panel computed signal.

Visible contributions reveal a hidden target and its ancestors by default. Set revealTarget: false when the package container's original visibility gate must remain authoritative.

NgRx state

Feature state is built with @ngrx/signals and @ngrx/signals/entities. Install a compatible NgRx Signals version alongside Angular; it is a peer dependency so the host and package always share one NgRx runtime.

Most package stores are root-provided and can be injected directly:

import {CmsAuthStore} from '@believablecreations/bc-app-cms/auth';
import {MediaStore} from '@believablecreations/bc-app-cms/media';

const auth = inject(CmsAuthStore);
const media = inject(MediaStore);

Editor/draft stores that should not share state across concurrent screens are exported for route- or component-level providers. Package-owned screens provide those scoped stores themselves.

Content Security Policy and Trusted Types

The root entry point exports immutable defaults and an additive policy builder:

import {
  CmsSecurityPolicyBuilder,
  DEFAULT_CMS_CSP_DIRECTIVES,
  DEFAULT_CMS_TRUSTED_TYPE_POLICIES,
} from '@believablecreations/bc-app-cms';

const policy = new CmsSecurityPolicyBuilder()
  .whitelist('connect-src', 'https://cms.example.com', 'wss://cms.example.com')
  .blacklist('script-src', "'wasm-unsafe-eval'")
  .whitelistTrustedTypePolicies('my-editor-policy')
  .blacklistTrustedTypePolicies('angular#unsafe-bypass')
  .build(requestNonce);

Allowlist/whitelist entries extend the package defaults. Blocklist/blacklist entries are evaluated last and therefore always win. disableDirectives() can remove an entire directive. For non-fluent configuration, use createCmsContentSecurityPolicy({nonce, allowlist, blocklist}).

provideBelievableCms() also installs the package's DOMPurify-backed default Trusted Types policy in the browser. This supplies both TrustedHTML for Quill and other reviewed editor integrations and restricted TrustedScriptURL handling for same-origin, analytics, Square, and package-supported loaders. Applications using the policy builder therefore do not need an inline default policy. Add an application-specific dynamic script origin only when required:

provideBelievableCms({
  apiUrl: 'https://cms.example.com/api',
  trustedTypes: {
    allowedScriptOrigins: ['https://scripts.example.com'],
  },
});

For a host that treats every DOM assignment in the CMS document as trusted, enable the permissive default policy. The CSP script-src directive still controls which script resources the browser may execute:

provideBelievableCms({
  apiUrl: 'https://cms.example.com/api',
  trustedTypes: {trustAll: true},
});

Dependency tree

The arrows below mean “imports or composes.” The consuming application sits at the top; the root package supplies configuration, URL construction, HTTP access, realtime adapters, SSR tokens, branding, and security policy helpers used throughout the feature entry points.

flowchart TD
  APP["Consuming Angular application"] --> ROOT["@believablecreations/bc-app-cms (root)"]
  APP --> ROUTES["/routes"]
  APP --> SHELL["/shell"]
  APP --> FEATURES["Feature entry points"]

  ROUTES --> LEGACY["/legacy-ui"]
  ROUTES --> PAGES["/pages"]
  ROUTES --> AUTH["/auth"]
  ROUTES --> ACL["/access-control"]

  SHELL --> ROOT
  SHELL --> AUTH
  SHELL --> ACL
  SHELL --> CONFIG["/config"]
  SHELL --> SHARED["/shared"]
  SHELL --> MEDIA["/media"]
  SHELL --> EMAIL["/email"]
  SHELL --> NOTIFY["/notifications"]
  SHELL --> STORE["/store"]
  SHELL --> USERS["/users"]
  SHELL --> SQUARE["/square"]

  FEATURES --> ROOT
  FEATURES --> AUTH
  FEATURES --> ACL

  STORE --> USERS
  STORE --> MEDIA
  STORE --> SHIPPING["/shipping"]
  SQUARE --> ACL
  USERS --> MEDIA
  PAGES --> SHARED
  CONTACT["/contact"] --> SHARED

  LEGACY --> ROOT
  LEGACY --> FEATURES

Entry-point dependencies

| Entry point | Direct package dependencies | Main external dependencies | | --- | --- | --- | | root | none | Angular core/common, RxJS | | routes | legacy-ui, pages, auth, access-control, shell (tests/link validation) | Angular Router | | shell | root, shared, auth, access-control, config, media, notifications, store, users, email, square | Material/CDK, service worker, Socket.IO, Font Awesome | | legacy-ui | root plus most feature entry points | Material/CDK, NgRx Signals, Quill, Monaco, Square SDK, Focus Point | | access-control | root, auth | Angular HTTP/Router, NgRx Signals | | auth | root | Angular HTTP/Router/Forms, NgRx Signals, RxJS | | blog | root, auth, access-control | Angular Router/Forms, NgRx Signals | | config | root, legacy-ui routes | Angular HTTP/Router, NgRx Signals | | contact | root, auth, access-control, shared | Angular Forms/Router, NgRx Signals | | email | root, auth, access-control | Angular HTTP/Router, NgRx Signals | | media | root, auth, access-control | Angular HTTP/Router, NgRx Signals, Focus Point | | media-config | root | Angular HTTP, NgRx Signals | | notifications | root, auth | Angular HTTP/Router, RxJS | | pages | root, auth, access-control, shared | Angular Router/Forms, NgRx Signals | | shared | root | Angular Forms, libphonenumber-js | | shipping | root, auth, access-control | Angular HTTP/Router/Forms, NgRx Signals | | square | root, auth, access-control | Angular HTTP/Router, NgRx Signals, Square SDK types | | store | root, auth, access-control, users, media, shipping | Angular Router/Forms, NgRx Signals, Square Web SDK | | system | root, auth, access-control | Angular HTTP/Router, NgRx Signals | | users | root, auth, access-control, media | Angular HTTP/Router, NgRx Signals | | api | compatibility layer; generally independent of newer feature stores | Angular HTTP | | smoke-consumer | imports every public entry point | TypeScript compiler only |

Layering rules

  1. The root entry point must not import feature entry points.
  2. Feature HTTP services should depend on the root CmsApiClient.
  3. Administration routes depend on authGuard and CanAccessGuard().
  4. Shared UI may depend on stable feature stores, but domain features should avoid depending on shell.
  5. Cross-domain models should be referenced from their owning public entry point.
  6. The route composer may depend on every route family; features must not depend on the route composer.
  7. Consumers must import public package paths only, never src/lib paths.

Peer dependencies are installed once by the consuming application. They are not bundled into this package, which prevents duplicate Angular, NgRx, Material, editor, payment, or icon runtimes.