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

@acedatacloud/core

v0.28.3

Published

Shared frontend core for AceDataCloud's browser apps (AuthFrontend / Nexior / PlatformFrontend): http client factory, telemetry, fingerprint, chunk-load recovery, locale + surface helpers, and shared types.

Readme

@acedatacloud/core

Shared frontend core for AceDataCloud's three browser apps:

These apps had independently re-implemented the same plumbing (axios interceptors, chunk-load recovery, telemetry, fingerprint, locale resolution) and drifted on the details. This package lifts the correctness-sensitive duplication into one place so the apps stop diverging on the parts where divergence causes real auth / observability bugs.

Distribution — published npm package

Consumed via a normal package.json dependency (no submodule, no @common alias):

npm install @acedatacloud/core

The package is built with plain tsc to ESM (no Vite library mode) so any consumer's bundler (Vite 8 / 7 / 2) transpiles it cleanly. CI auto-publishes on merge to main, version-gated: a merge publishes only when package.json's version is not already on npm. To ship a release, bump the version in package.json in your PR.

Subpath entry points

Import only what you need — peer-dependent modules are subpath-only so they tree-shake:

import { createChunkLoadErrorHandler, makeGetLocale, isWechat } from '@acedatacloud/core/core';
import { createHttpClient } from '@acedatacloud/core/http';           // peer: axios
import { createTelemetry } from '@acedatacloud/core/telemetry';       // peer: aegis-web-sdk (optional)
import { createFingerprintResolver } from '@acedatacloud/core/fingerprint';
import type { IUser, IConnection } from '@acedatacloud/core/types';
import type { ITranslationEnableRequest, ITranslationEnableResponse } from '@acedatacloud/core/types';
import { CURRENCY_LABEL_MAPPING, LOCALE_CURRENCY_MAPPING } from '@acedatacloud/core/constants';
import { debug, getBaseUrlAuth } from '@acedatacloud/core/utils';
import { replaceBrandText } from '@acedatacloud/core/brand-spacing';
import { buildUsageAnalytics, formatUsageAmount, formatUsageElapsed } from '@acedatacloud/core/usage';
import { extractX402PaymentError, resolveX402PaymentError } from '@acedatacloud/core/x402';

The root entry (@acedatacloud/core) re-exports the dependency-free surface (core, types, constants, utils).

Usage analytics

@acedatacloud/core/usage converts API aggregate rows into stacked-bar series, doughnut slices, and the complete API breakdown used by PlatformFrontend and Nexior. It preserves duplicate-row summation, date ordering, the 99% spend threshold, the 20-series cap and the single-leftover exception. Pass the translated “Others” title; the helper adds the folded API count. Amounts stay in Credits. The module has no Chart.js, Vue, HTTP, or store dependency.

The consumers retain request filters, locale selection, loading/error state, stale-response guards and Chart.js options. formatUsageAmount and formatUsageElapsed preserve their existing table and tooltip formatting.

Shared components

Import the shared stylesheet once in the application entry, then import components from the dedicated subpath:

import '@acedatacloud/core/styles.css';
import { Pagination } from '@acedatacloud/core/components';

Pagination preserves the existing Nexior and PlatformFrontend props and change event contract. Its round controls use the shared --adc-radius-round token in styles.css.

The shared crop viewport keeps zoom, rotation, flip, replacement controls, and the crop frame consistent across the three frontends. Applications still own file selection, dialogs, uploads, and brand processing:

import { ImageCropperViewport } from '@acedatacloud/core/components/image-cropper-viewport';
import '@acedatacloud/core/image-cropper.css';
import 'vue-advanced-cropper/dist/style.css';

Pass localized labels, src, aspectRatio, and optionally shape, imageRestriction, controlSize, or checkerboard. The exposed getResult() returns null for an empty crop. Set --adc-image-cropper-height on the component for the viewport height.

BackNavigation, StatusBadge, MetaTag, ActionChip, and FilterChip use the same stylesheet:

<BackNavigation :as="RouterLink" :to="parentRoute">All campaigns</BackNavigation>
<StatusBadge tone="info" density="compact">Submitted</StatusBadge>
<MetaTag tone="brand">Vision</MetaTag>
<ActionChip @click="manageKey">Manage key</ActionChip>
<FilterChip :selected="imagesOnly" @click="toggleImages">Images</FilterChip>

The application imports RouterLink; the shared component has no router/store dependency. BackNavigation defaults to a non-submitting button, supports as="a" plus href, and forwards routing attributes and events. Parent navigation, history fallbacks, wizard steps, dismissals, OAuth callbacks and dirty guards remain application-owned. An icon-only workspace return needs icon-only and an action-specific aria-label; variant="inverse" supports dark hero surfaces.

Display badges have a soft background, 8px radius, 12px text and 24px height; density="compact" is the 20px table/list variant. Tones are neutral / brand / info / success / warning / danger. Existing primary resolver results map to brand; empty/unknown results map to neutral. State-to-tone mapping remains application-owned. Use MetaTag for information, ActionChip for an action and FilterChip for controlled aria-pressed selection. Static badges do not create live regions. Navigation/chips have 44px touch targets. Semantic foreground/background pairs support light/dark contrast; neutral/brand follow application theme/tenant accent.

The control adapter also normalizes existing Element Plus tags, including closable/interactive tags, to this geometry and soft tone treatment. size="small" is compact; legacy round, effect and large do not create competing shapes or fills. Keep application-specific interactions on the Element tag when a display badge would lose them.

Shared Markdown

import {
  MarkdownRenderer,
  createMarkdownRenderer,
} from "@acedatacloud/core/markdown";
import "@acedatacloud/core/markdown.css";

MarkdownRenderer takes source, reactive options, anchor, linkTarget, and htmlPolicy props. The default sanitize policy supports native audio/video, rich text presentation styles, task lists, tables, highlighted code and KaTeX ($, $$, \(, \[, and fenced math). Media always have controls and preload="none"; scripts, event handlers, frames and unsafe URLs are removed. Styles follow the application's Element Plus tokens, including dark mode.

Use htmlPolicy="escape" for literal raw HTML. Existing anonymous Studio surfaces keep the markdownSanitize injection / sanitize prop escape guard. trusted is available only for existing trusted, generated document content. Heading anchors are opt-in; in-page links keep their current browsing context. Citation cards, copy buttons, navigation and application-specific styling stay with consumers. The pure renderer and Vue adapter also work during SSR.

Consumers use the normal published npm package. Merge and publish the core release before merging adoption PRs in dependent repositories.

Design tokens

styles.css also defines the shared visual baseline without globally styling application elements:

  • theme-aware color, text, surface, and border aliases;
  • the 4 / 8 / 12 / 16 / 20 / full radius scale with small / control / card / dialog semantics;
  • a 4px spacing grid;
  • shared font-family, size, weight, line-height, and letter-spacing tokens.
  • button levels xs/sm/md/lg/xl at 20/24/32/40/48px; inline Copy uses xs, prompt expand uses sm, and code-block Copy keeps its 30px special case; Element Plus buttons retain their native small/default/large sizes unless an individual component opts in;
  • focus outline/ring, elevation, motion, and stacking-layer tokens;
  • reduced-motion duration overrides.

Consumers opt in by mapping their existing root variables and component styles to --adc-*. Runtime accent colors and light/dark surfaces remain owned by each application's Element Plus theme.

Core control adapter

Import the control adapter after vendor and application styles — including Tailwind — so its variant-safe Element Plus contract wins without !important:

import '@acedatacloud/core/styles.css';
import './assets/scss/style.scss';
import './assets/css/tailwind.css';
import '@acedatacloud/core/controls.css';

Keeping controls.css last is load-bearing, not cosmetic. It carries an svg { display: inline-block } reset that undoes Tailwind preflight's svg { display: block } (which otherwise breaks text-align: center on icons). Both selectors have the same specificity, so the reset only wins by coming later — import Tailwind after controls.css and it silently stops working.

The adapter standardizes Button, Input, Select, Textarea, Card, Dialog, and MessageBox while preserving Element's link/text/circle sizes, error states, input-group seams, and card shadow modes. Applications can retain product-specific card styling through --adc-control-card-border, --adc-control-card-shadow, --adc-control-card-shadow-hover, and --adc-control-dialog-shadow; because dialogs and message boxes are teleported, set overlay hooks on :root or body.

Use card-gap on card groups and card-section-gap for the space below a card section. Both use --adc-card-gap, which defaults to the 20px spacing token; an app can set its own value on :root. Element rows keep their own horizontal gutter, and a guttered el-col.grid.card-gap stays a grid.

For groups of cards, add card-gap to their grid, flex container, or el-row. It keeps a shared 20px gap between cards; on el-row it preserves Element Plus's horizontal gutter and adds only the vertical gap needed when columns wrap.

Semantic icons

@acedatacloud/core/icons defines one Lucide glyph for each product semantic. Brand logos remain official SVG/brand assets and are not mapped to Lucide. @acedatacloud/core/icons/components statically re-exports the complete reviewed semantic set; the original single-icon subpaths remain available for compatibility.

Consumers that use icon subpaths must exact-pin the tested peer in the same adoption PR:

npm install --save-exact @lucide/[email protected]

The manifest is a review source, not a dynamic runtime resolver. Consumer code uses named imports, for example import { AddIcon, SearchIcon } from '@acedatacloud/core/icons/components'; bundlers tree-shake unused named re-exports. Do not use import * as Icons, Lucide DynamicIcon, or arbitrary icon-name strings in production bundles. Legacy call sites are migrated by product meaning, never by globally replacing a Font Awesome glyph.

Layout

src/
├── core/            # Pure TS, zero framework deps
│   ├── chunkLoadError.ts   createChunkLoadErrorHandler({ storagePrefix })
│   ├── surface.ts          isWechat(), isMobile()
│   └── locale.ts           makeGetLocale({ supportedLocales, defaultLocale })
├── http/            # peer: axios
│   └── createHttpClient.ts createHttpClient(config) — request/response interceptor contract
├── telemetry/       # peer: aegis-web-sdk (optional, dynamically imported)
│   └── createTelemetry.ts  createTelemetry({ projectId, hostUrl }) — Tencent RUM glue
├── fingerprint/     # FingerprintJS loader injected (no SDK dep — v4/v5 both work)
│   └── createFingerprintResolver.ts
├── types/           # Pure TypeScript interfaces (user, connection, skill, oauthApp)
├── brand-spacing/   # Unicode-aware boundaries; consumers own source/replacement policy
├── constants/       # base URLs plus shared locale/currency mappings
├── utils/           # getBaseUrl* helpers plus the shared console.debug alias
└── index.ts         # root re-export of the dependency-free surface

Design notes

  • Factories, not singletons. Everything that differed across apps (timeout, header casing, where the token/userId/fingerprint come from, what a 401 does, RUM ext-slot mapping, FingerprintJS version) is injected via config. The package never imports a store, a router, or vuex.
  • What is intentionally not here: Vuex stores, app-specific routing/auth helpers, brand identity/policy, and business workflows. brand-spacing is a dependency-free text-boundary helper; each consumer owns its source variants and replacement brand. Element Plus components are shared only when the existing app implementations and public contracts are the same.

Develop

npm install
npm run typecheck   # tsc -p tsconfig.json (no emit)
npm test            # vitest (jsdom)
npm run build       # tsc -p tsconfig.build.json -> dist/

License

Private — AceDataCloud internal.

User acquisition context

@acedatacloud/core/attribution provides createAcquisitionContext for the four UTM labels and a capture timestamp. It only reads/writes browser cookies; it has no fetch, visit handle, identity binding, event queue or authentication dependency. Explicit tagged landings replace the complete tuple. Untagged navigation keeps it without renewing its seven-day expiry. Signup reads the context once; the Auth backend freezes it in existing User.metadata. Legacy cookies without a timestamp remain legacy evidence, rather than receiving an invented first-touch time.

The browser predicate respects DNT/GPC, saved opt-out, public invoice pages and first-party host boundaries. Storage failures do not affect page navigation. The acquisition rules are generated from PlatformBackend/config/marketing_attribution.json. This package contains only the acquisition projection, not service entries or channel inventories. The backend-owned exporter generates both the pinned JSON and TypeScript constant; UTM_KEYS is derived from that constant. Adding an MCP or campaign does not require a core release. Field/window changes require a versioned core release before consumer adoption. See PlatformBackend/scripts/ECOSYSTEM_CONTRACTS.md.