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

@c80/core

v1.2.2

Published

Infra Angular compartida del ecosistema barman (StorageService SSR-safe, ImageService de Cloudflare R2, factory del interceptor de auth, la sesion canonica email/password con guards y el ErrorHandler global de monitoreo). Fuente unica consumida por kyron-

Downloads

634

Readme

@c80/core

Infra Angular compartida del ecosistema barman. Fuente unica de los servicios de infraestructura que antes vivian duplicados (copias identicas tras la reconciliacion D21) en kyron-front y chillbox. Peer de Angular ^21, publicada a npm igual que @c80/ui y @c80/types (los fronts son repos separados, no un monorepo: npm es el canal de distribucion).

Alcance v1.0.0 — SOLO los 3 servicios de infra reconciliados a un canonico identico:

  • StorageService — acceso a localStorage SSR-safe + try/catch.
  • ImageService — construccion de URLs de Cloudflare R2 (avatares/productos).
  • createAuthInterceptor(...) — factory del interceptor de auth (Bearer + reaccion ante 401).
  • Sesion email/password canonica (1.1.0)C80AuthSessionService (token + perfil signal + permisos), c80AuthGuard / c80PermissionGuard / c80ProfileResolver y c80AuthInterceptor listo. La usan kyron y midas via provideC80Core({ image, auth: {...} }); chillbox NO (login Google propio, sigue con createAuthInterceptor).
  • ErrorHandler global de monitoreo (1.2.0)C80GlobalErrorHandler reporta los errores de runtime del front a un endpoint (POST client-error) con fetch directo, truncado y throttled, y es fail-silent. Registrar con provideC80Core({ ..., monitoring: { clientErrorUrl } }) + provideC80GlobalErrorHandler(). Lo usan los 3 fronts (extraido de chillbox).

NO incluye notification ni base-crud (son solo de kyron, sin duplicacion).

Que exporta el barrel (@c80/core)

| Export | Tipo | Notas | |---|---|---| | StorageService | @Injectable({providedIn:'root'}) | set<T> / get<T> / remove / clear / has. No requiere config. | | ImageService | @Injectable({providedIn:'root'}) | getAvatarUrl / getProductImageUrl / isR2Url. Requiere C80_CORE_CONFIG.image. | | createAuthInterceptor(config) | (AuthInterceptorConfig) => HttpInterceptorFn | Factory; el front arma su authInterceptor delegando aca. | | AuthInterceptorConfig | interface | Estrategia de auth del front (ver abajo). | | provideC80Core(config) | (C80CoreConfig) => Provider | Registra la config de instancia en el bootstrap. | | C80_CORE_CONFIG | InjectionToken<C80CoreConfig> | Token de la config; usar provideC80Core en vez de proveerlo a mano. | | C80CoreConfig / C80ImageConfig / C80AuthSessionConfig | interface | Forma de la config (auth es opcional). | | C80AuthSessionService | @Injectable({providedIn:'root'}) | Sesion email/password: login / logout / initialize / user signal / hasPermission*. Requiere C80_CORE_CONFIG.auth. | | c80AuthGuard / c80PermissionGuard | CanActivateFn | Guards de sesion y de permisos por route.data (C80PermissionGuardData). | | c80ProfileResolver | ResolveFn | Garantiza el perfil cargado y lo entrega a la ruta. | | c80AuthInterceptor | HttpInterceptorFn | Interceptor listo (Bearer salvo login, 401 transparente). | | C80AuthCredentials / C80SessionUser / C80SessionRole / C80LoginResult | interface | Tipos estructurales minimos de la sesion (castear al contrato pleno en la app). |

Config de instancia (obligatoria para ImageService)

ImageService depende de la config de R2, que es config de instancia (el publicUrl del bucket cambia por entorno) y NO puede hardcodearse en la lib. Cada front la provee con su environment.image:

// app.config.ts / main de cada front
import { provideC80Core } from '@c80/core';
import { environment } from '@environments/environment';

providers: [
  provideC80Core({ image: environment.image }),
]

environment.image de ambos fronts ya tiene la forma exacta de C80ImageConfig ({ publicUrl, avatarsFolder, productsFolder, imageFormat }), asi que se pasa directo.

StorageService no necesita config. Si un front usa solo StorageService, provideC80Core igual es inofensivo (barato); pero si usa ImageService sin proveer la config, el inject(C80_CORE_CONFIG) falla en runtime — proveerlo siempre.

Registro del interceptor de auth

La FORMA compartida es "Bearer salvo login + reaccion global ante 401". Los 3 puntos que divergen por diseño se parametrizan (no se unifican): endpoint de login, fuente del token y handler del 401. Cada front escribe un interceptor delgado que inyecta SUS deps y delega en createAuthInterceptor:

// chillbox — src/app/shared/interceptors/auth.interceptor.ts
import type { HttpInterceptorFn } from '@angular/common/http';
import { inject } from '@angular/core';
import { createAuthInterceptor, StorageService } from '@c80/core';
import { AuthService } from '../services/auth.service';
import { STORAGE_KEYS, API_ENDPOINTS } from '@shared/constants';

export const authInterceptor: HttpInterceptorFn = (req, next) => {
  const storage = inject(StorageService);
  const auth = inject(AuthService);
  return createAuthInterceptor({
    getToken: () => storage.get<string>(STORAGE_KEYS.TOKEN),
    isLoginRequest: (r) => r.url === API_ENDPOINTS.auth.googleLogin,
    onUnauthorized: () => auth.logout(),
  })(req, next);
};
// kyron — src/app/core/interceptors/auth.interceptor.ts
import type { HttpInterceptorFn } from '@angular/common/http';
import { createAuthInterceptor } from '@c80/core';
import { TokenStorage } from '@core/utils/token-storage.util';

// El 401 lo maneja notification.interceptor => NO se pasa onUnauthorized (interceptor transparente a
// la respuesta, mismo camino que hoy).
export const authInterceptor: HttpInterceptorFn = createAuthInterceptor({
  getToken: () => TokenStorage.get(),
  isLoginRequest: (r) => r.url.includes('/auth/login'),
  skipBearerOnLoginRequest: true,
});

AuthInterceptorConfig

  • getToken: () => string | null — de donde sale el token.
  • isLoginRequest?: (req) => boolean — marca el request de login (default: ninguno). Se usa para no desloguear ante su 401 y, si skipBearerOnLoginRequest, para no adjuntarle el Bearer.
  • skipBearerOnLoginRequest?: boolean — no adjunta Bearer al login (kyron true; chillbox omite = false).
  • onUnauthorized?: () => void — accion ante un 401 que no sea del login (chillbox: logout). Si se omite, el interceptor no envuelve la respuesta (lo maneja otra pieza; caso kyron).

Publicacion

Mismo flujo que @c80/ui: pnpm publish:core (corre gate + bump + build del dist/core + publish). La v1.0.0 se publico manualmente (sin bump) desde dist/core.