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

@prism-reporting/core

v0.1.0-beta.1

Published

Core ReportSpec types, validation, resolution, and reporting context contracts.

Downloads

26

Readme

@prism-reporting/core

Core types, engine, and interfaces for the reporting beta foundation.

Beta status

@prism-reporting/core is currently in beta.

  • The DSL and runtime contracts are expected to evolve.
  • Breaking changes may happen without long deprecation windows during this phase.
  • This package is intended as a foundation for integrations, not a final product surface.
  • External pull requests are not being accepted right now; please open an issue if a capability you need is missing.

ReportSpec v1

The ReportSpec is a structured DSL that describes reports. AI tools (future phase) will generate and modify ReportSpec—they do not produce raw HTML or control UI libraries directly.

Required Fields (Safe for AI)

| Field | Type | Required | Description | |-------|------|----------|-------------| | id | string | Yes | Unique report identifier | | title | string | Yes | Display title | | layout | "singleColumn" | "twoColumn" | Yes | Page layout | | dataSources | Record<string, DataSourceSpec> | Yes | Named data sources | | filters | FilterSpec[] | Yes | Filter definitions (may be empty) | | widgets | WidgetSpec[] | Yes | Visual widgets | | groups | ReportGroupSpec[] | No | Optional logical widget groups used to scope filters to part of a report. | | presets | ReportSpecPreset[] | No | Optional named filter states (e.g. "This quarter"); host applies preset.filterState. | | version | string | No | Optional report version (e.g. "1.0", "2024.03"); exposed on ResolvedReport.version for UI display. | | refreshInterval | number | No | Optional interval in seconds; when set, the host should re-call resolveReport after that interval (engine does not implement timers). Hosts may cache by spec.id + filterState and TTL. | | layoutOptions | LayoutOptions | No | Optional columnGap / rowGap CSS hints for the report grid. | | sections | ReportSectionSpec[] | No | Optional titled widget groupings; widgets are referenced by id. | | tabs | ReportTabSpec[] | No | Optional tabbed layout; takes precedence over sections. | | owner | string | No | Optional owner (e.g. user id or email); pass-through for governance and UI (e.g. "Owner: {owner}"). | | author | string | No | Optional author (e.g. user id or email); pass-through for UI (e.g. "By {author}"). |

DataSourceSpec

| Field | Type | Required | Description | |-------|------|----------|-------------| | name | string | Yes | Unique name within the report | | query | string | Yes | Query identifier (passed to DataProvider.runQuery) | | params | Record<string, unknown> | No | Static default parameters | | delivery | { mode, pageSize?, maxRows? } | No | Explicit integration contract. Use paginatedList for table/list sources, fullVisual for full chart datasets and engine-side grouped summaries, summary for backend-aggregated KPI sources. |

FilterSpec Variants

  • SelectFilter: type: "select", options: { value, label }[], groupIds?, paramKey?
  • MultiSelectFilter: type: "multiSelect", options: { value, label }[], groupIds?, paramKey?
  • DateRangeFilter: type: "dateRange", groupIds?, paramKeyFrom?, paramKeyTo?
  • SearchFilter: type: "search", groupIds?, paramKey?, placeholder?
  • NumericRangeFilter: type: "numericRange", groupIds?, min?, max?, step?, paramKeyFrom?, paramKeyTo?

All filters require: id, label, dataSource (must reference a key in dataSources).

WidgetSpec Variants

  • TableWidget: type: "table", config.columns?: { key, label }[], config.summary?: { key, op }[], config.groupByKey?, config.groupAggregations?, config.drillDown?
  • CardViewWidget: type: "cardView", config.titleKey, optional config.subtitleKey, config.badges, config.metadata, config.primaryMetric, config.template
  • BarChartWidget: type: "barChart", config.categoryKey, config.valueKey
  • LineChartWidget / AreaChartWidget: config.categoryKey, config.valueKey, optional config.series
  • PieChartWidget / DoughnutChartWidget / SpiralChartWidget / FunnelChartWidget: config.categoryKey, config.valueKey
  • StackedBarChartWidget: config.categoryKey, config.series
  • ScatterChartWidget / BubbleChartWidget: config.xKey, config.yKey, optional or required config.zKey
  • TimelineViewWidget / GanttChartWidget: config.startDateKey, config.endDateKey, config.labelKey, optional config.groupKey, config.statusKey
  • KpiWidget: type: "kpi", config.valueKey, config.label?, optional aggregation/format/trend settings

All widgets require: id, dataSource, config. title, groupIds, width, and height are optional.

Sizing hints:

  • width / height are optional CSS size strings such as 100%, 320px, or 24rem.
  • The renderer enforces per-widget minimum sizes even when a smaller hint is provided.
  • Current minimums are exported as WIDGET_SIZE_CONSTRAINTS and available through getWidgetSizeConstraints():
    • table: min 320px wide, 180px tall
    • cardView: min 320px wide, 220px tall
    • bar/line/stacked charts: min 320px wide, 260px tall
    • KPI: min 180px wide, 80px tall

Safe-for-AI Constraints

  1. Referential integrity: Filter and widget dataSource values must exist in dataSources.
  2. Unique IDs: Widget and filter id values must be unique within the report.
  3. No arbitrary layout: Use only singleColumn or twoColumn—no pixel-level control.
  4. Stable schema: Adding new filter/widget types requires schema updates; AI should only use documented types.

DataProvider Interface

The host implements DataProvider to provide data. The engine never accesses databases directly.

interface DataProvider {
  runQuery(
    request: {
      name: string;
      params?: Record<string, unknown>;
      execution?: {
        deliveryMode: "paginatedList" | "fullVisual" | "summary";
        page?: number;
        pageSize?: number;
        maxRows?: number;
      };
    }
  ): Promise<
    | unknown[]
    | {
        kind?: "rows";
        data: unknown[];
        totalCount?: number;
        pagination?: {
          page: number;
          pageSize: number;
          totalCount?: number;
          hasMore?: boolean;
        };
      }
    | {
        kind: "limitExceeded";
        totalCount: number;
        limit: number;
        message?: string;
      }
  >;
}

Framework expectations:

  • paginatedList: backend should use execution.page / execution.pageSize and return rows plus pagination metadata.
  • fullVisual: backend must not paginate. Return all rows when they fit under execution.maxRows; otherwise return kind: "limitExceeded" with totalCount.
  • summary: backend returns already-aggregated rows for KPIs/summary widgets.

When a host returns the object form, the engine preserves pagination or limitExceeded metadata on the resolved query so the UI can render table paging controls and explicit “too much data” messages for visuals.

Engine

  • validateReportSpec(spec, context?, options?): Returns { version, valid, errors, diagnostics }. Optional options.policy(spec) runs after structural validation; when the policy returns allowed: false, policy errors are added to diagnostics and valid is set to false. Hosts can supply a policy for governance (e.g. max widgets, allowed query names).
  • resolveReport(spec, dataProvider, filterState?, options?): Validates, runs queries with merged filter params, returns ResolvedReport. Optional options.onAudit(event) is called with a minimal audit event on success or error so hosts can log to their audit system.

validateReportSpec supports optional grounding context:

  • availableQueries?: string[]
  • availableFields?: Record<string, string[]>

When grounding context is provided, the validator can also catch:

  • unknown dataSource.query values
  • unknown widget field references for the selected query
  • invalid enum-like values and missing type-specific config
  • duplicate filter ids in addition to duplicate widget ids

Shareable URLs (filter state in URL)

Hosts can persist filter state in the URL so links are shareable. Use:

  • serializeFilterStateToSearchParams(filterState, spec.filters) – returns a query string (e.g. ?status=NEW&dueDateFrom=2024-01-01) from current filter state.
  • parseFilterStateFromSearchParams(search, spec.filters) – parses window.location.search (or any query string) into Record<string, unknown> filter state.

Conventions: single-value filters use the filter id as the param key; multiSelect uses the same key with comma-separated values; dateRange/numericRange use idFrom and idTo. On load, parse the URL and pass the result as initial filter state; on filter change, call serializeFilterStateToSearchParams and update the URL with history.replaceState or pushState.

Save/load reports

Hosts may persist a report by saving the spec as JSON and restore it later. Use serializeReportSpecToJson(spec) to get a string (e.g. for localStorage or a server API), and parseReportSpecFromJson(json) to parse it back; the parser returns { ok: true, spec } or { ok: false, error }. No backend or database is required—persistence is the host's responsibility.

Export

  • CSV: Use exportTableToCsv(columns, rows) with resolved table columns and rows to produce a CSV string. The react-ui table widget exposes an "Export CSV" button that uses this.
  • PDF: PDF export is not currently exposed in the react-ui renderer. If this is reintroduced later, it will likely use the browser print dialog rather than a dedicated PDF library.

Reporting context contract

Shared types for base and semantic reporting context, and the context provider interface, are exported from @prism-reporting/core. Both the MCP package and application code (e.g. starter example) can use these types.

Base reporting context

  • BaseReportingContext: source?, tenantId?, queries: QueryCatalogEntry[]
  • QueryCatalogEntry: name, description?, fields?, params?, notes?

Base context drives deterministic validation and runtime behavior (e.g. validateReportSpec grounding).

Semantic reporting context (optional)

  • SemanticReportingContext: queryAliases?, fieldAliases?, examples?, clarificationHints?
  • Element types: QueryAliasEntry, FieldAliasEntry, SemanticExampleEntry, ClarificationHintEntry

Semantic context is for AI grounding only; it must not redefine validation rules.

Context provider interface

  • ReportingContextProvider:
    • getBaseContext(input?): Promise<BaseReportingContext> (required)
    • getSemanticContext(input?): Promise<SemanticReportingContext | null> (optional method)

Implementations may be local (e.g. starter reading from query catalog) or remote. The MCP server and app both consume context via this provider.

Component Registry

The ComponentRegistry interface maps primitives (table, cardView, barChart, kpi, filterBar, and the other supported visual widgets) to React components. Hosts can provide custom implementations (e.g., Ant Design, MUI) without changing the spec.

Example: Natural Language → ReportSpec

Request: "Show me tasks by status with a date filter"

Generated ReportSpec (conceptual):

{
  "id": "tasks-by-status",
  "title": "Tasks by Status",
  "layout": "singleColumn",
  "dataSources": { "tasks": { "name": "tasks", "query": "tasks" } },
  "filters": [
    { "type": "select", "id": "status", "label": "Status", "dataSource": "tasks", "options": [...] },
    { "type": "dateRange", "id": "dateRange", "label": "Due Date", "dataSource": "tasks" }
  ],
  "widgets": [
    { "type": "table", "id": "t1", "dataSource": "tasks", "config": { "columns": [...] } }
  ]
}