metrickit 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/LICENSE +21 -0
  3. package/README.md +379 -0
  4. package/dist/cache-redis.d.ts +10 -0
  5. package/dist/cache-redis.js +24 -0
  6. package/dist/cache-utils.d.ts +5 -0
  7. package/dist/cache.d.ts +18 -0
  8. package/dist/catalog.d.ts +12 -0
  9. package/dist/define-metric.d.ts +37 -0
  10. package/dist/engine.d.ts +200 -0
  11. package/dist/filters/default-metadata.d.ts +28 -0
  12. package/dist/filters/index.d.ts +3 -0
  13. package/dist/filters/parse.d.ts +7 -0
  14. package/dist/filters/types.d.ts +19 -0
  15. package/dist/frontend/catalog.d.ts +24 -0
  16. package/dist/frontend/dashboard.d.ts +12 -0
  17. package/dist/frontend/format.d.ts +10 -0
  18. package/dist/frontend/index.d.ts +10 -0
  19. package/dist/frontend/markers.d.ts +19 -0
  20. package/dist/frontend/renderers.d.ts +14 -0
  21. package/dist/frontend/requests.d.ts +17 -0
  22. package/dist/frontend/stream-state.d.ts +14 -0
  23. package/dist/frontend/time.d.ts +5 -0
  24. package/dist/frontend/transport.d.ts +19 -0
  25. package/dist/frontend/types.d.ts +108 -0
  26. package/dist/frontend.d.ts +1 -0
  27. package/dist/frontend.js +752 -0
  28. package/dist/helpers/clickhouse.d.ts +27 -0
  29. package/dist/helpers/distribution.d.ts +15 -0
  30. package/dist/helpers/index.d.ts +6 -0
  31. package/dist/helpers/metric-type.d.ts +21 -0
  32. package/dist/helpers/pivot.d.ts +15 -0
  33. package/dist/helpers/prisma.d.ts +20 -0
  34. package/dist/helpers/timeseries.d.ts +6 -0
  35. package/dist/helpers.d.ts +1 -0
  36. package/dist/helpers.js +668 -0
  37. package/dist/index.d.ts +11 -0
  38. package/dist/index.js +1322 -0
  39. package/dist/orpc.d.ts +36 -0
  40. package/dist/orpc.js +1157 -0
  41. package/dist/registry.d.ts +269 -0
  42. package/dist/run-metrics.d.ts +14 -0
  43. package/dist/schemas/index.d.ts +4 -0
  44. package/dist/schemas/inputs.d.ts +19 -0
  45. package/dist/schemas/metric-type.d.ts +7 -0
  46. package/dist/schemas/output.d.ts +842 -0
  47. package/dist/schemas/time.d.ts +24 -0
  48. package/dist/time.d.ts +6 -0
  49. package/dist/type-guards.d.ts +7 -0
  50. package/package.json +91 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,21 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project follows a pragmatic `0.x` release policy:
7
+
8
+ - breaking API changes may still happen between minor releases
9
+ - supported public entry points are documented in `README.md`
10
+ - undocumented/internal utilities may change without notice
11
+
12
+ ## [0.1.0] - 2026-04-07
13
+
14
+ ### Added
15
+
16
+ - Initial release of the single-package `metrickit` library
17
+ - Core metrics engine, registry, runtime execution, and cache interfaces
18
+ - ORPC helpers via `metrickit/orpc`
19
+ - Redis cache adapter via `metrickit/cache-redis`
20
+ - Framework-neutral frontend helpers via `metrickit/frontend`
21
+ - Advanced helper utilities grouped under `metrickit/helpers`
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kristoffer Hansen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,379 @@
1
+ # metrickit
2
+
3
+ Type-safe metrics, dashboards, and transport primitives for TypeScript apps.
4
+
5
+ ## Features
6
+
7
+ - Strong TypeScript inference from metric definition to request, result, and dashboard usage
8
+ - A single engine that owns shared context, base filters, caching, and custom metric kinds
9
+ - Registry-driven execution so one metric list powers runtime lookup and compile-time typing
10
+ - Built-in metric kinds for KPI, time series, distribution, table, leaderboard, and pivot outputs
11
+ - Extensible custom metric kinds through `engine.defineMetric(kind, def)`
12
+ - Pluggable caching through `CacheAdapter` with a Redis adapter at `metrickit/cache-redis`
13
+ - ORPC-friendly helpers at `metrickit/orpc`
14
+ - Framework-neutral frontend helpers at `metrickit/frontend`
15
+
16
+ ## Install
17
+
18
+ ```bash
19
+ bun add metrickit zod
20
+ ```
21
+
22
+ or
23
+
24
+ ```bash
25
+ npm install metrickit zod
26
+ ```
27
+
28
+ `zod` is a peer dependency so your app and `metrickit` share the same Zod version.
29
+
30
+ ## Runtime Support
31
+
32
+ - Node.js `>=18`
33
+ - Bun `>=1.0`
34
+
35
+ ## Package Entry Points
36
+
37
+ - `metrickit`: engine, registry, schemas, runtime helpers, cache interfaces, and filters
38
+ - `metrickit/orpc`: typed router helpers for `runMetrics`, streaming, and catalog discovery
39
+ - `metrickit/cache-redis`: Redis cache adapter
40
+ - `metrickit/frontend`: typed frontend request, dashboard, stream-state, catalog, and formatting helpers
41
+ - `metrickit/helpers`: advanced helper utilities for ClickHouse, Prisma, distributions, timeseries shaping, pivot building, and metric-type helpers
42
+
43
+ ## Supported Public API
44
+
45
+ The normal supported path is:
46
+
47
+ - `createMetricsEngine()`
48
+ - `engine.define*Metric(...)`
49
+ - `engine.createRegistry(...)`
50
+ - `runMetrics()` or `createMetricsRouter(...)`
51
+ - optional frontend helpers from `metrickit/frontend`
52
+
53
+ The following are also supported, but are more advanced:
54
+
55
+ - schemas and filter utilities re-exported from `metrickit`
56
+ - `metrickit/helpers` for framework/database-specific helper utilities
57
+
58
+ Avoid depending on internal source paths or unpublished files inside `dist`.
59
+
60
+ ## Core Workflow
61
+
62
+ 1. Create a metrics engine with your shared context and base filters.
63
+ 2. Define metrics through that engine.
64
+ 3. Register the metrics once in a registry.
65
+ 4. Execute the registry directly or expose it through ORPC.
66
+ 5. Reuse the same registry types in frontend helpers.
67
+
68
+ ## Quick Start
69
+
70
+ ```ts
71
+ import { z } from 'zod'
72
+ import {
73
+ BaseFiltersSchema,
74
+ createMetricsEngine,
75
+ defineKpiOutput,
76
+ runMetrics,
77
+ } from 'metrickit'
78
+ import { createMetricsRouter } from 'metrickit/orpc'
79
+ import { redisCacheAdapter } from 'metrickit/cache-redis'
80
+
81
+ const FunnelOutputSchema = z.object({
82
+ kind: z.literal('funnel'),
83
+ steps: z.array(
84
+ z.object({
85
+ key: z.string(),
86
+ value: z.number(),
87
+ }),
88
+ ),
89
+ })
90
+
91
+ const AppFiltersSchema = BaseFiltersSchema.extend({
92
+ country: z.string().optional(),
93
+ })
94
+
95
+ const metricsEngine = createMetricsEngine<
96
+ { db: unknown; viewerId: string },
97
+ z.infer<typeof AppFiltersSchema>,
98
+ { funnel: typeof FunnelOutputSchema }
99
+ >({
100
+ baseFilters: AppFiltersSchema,
101
+ cache: redisCacheAdapter(redisClient),
102
+ customKinds: {
103
+ funnel: FunnelOutputSchema,
104
+ },
105
+ })
106
+
107
+ const totalRevenueMetric = metricsEngine.defineKpiMetric({
108
+ key: 'revenue.total',
109
+ description: 'Total revenue',
110
+ supportsTimeRange: true,
111
+ filterSchema: AppFiltersSchema,
112
+ async resolve({ filters }) {
113
+ return defineKpiOutput({
114
+ value: filters.country === 'DK' ? 1200 : 900,
115
+ label: 'Revenue',
116
+ })
117
+ },
118
+ })
119
+
120
+ const pipelineFunnelMetric = metricsEngine.defineMetric('funnel', {
121
+ key: 'pipeline.funnel',
122
+ description: 'Pipeline conversion funnel',
123
+ supportsTimeRange: false,
124
+ filterSchema: AppFiltersSchema,
125
+ async resolve() {
126
+ return {
127
+ kind: 'funnel',
128
+ steps: [
129
+ { key: 'visits', value: 1200 },
130
+ { key: 'signups', value: 240 },
131
+ ],
132
+ }
133
+ },
134
+ })
135
+
136
+ export const metricsRegistry = metricsEngine.createRegistry([
137
+ totalRevenueMetric,
138
+ pipelineFunnelMetric,
139
+ ] as const)
140
+
141
+ export type MetricsRegistry = typeof metricsRegistry
142
+
143
+ const result = await runMetrics({
144
+ registry: metricsRegistry,
145
+ request: {
146
+ metrics: [
147
+ { key: 'revenue.total', filters: { country: 'DK' } },
148
+ { key: 'pipeline.funnel', requestKey: 'pipeline' },
149
+ ],
150
+ compareToPrevious: true,
151
+ },
152
+ createContext: () => ({
153
+ db,
154
+ viewerId: 'viewer_1',
155
+ }),
156
+ })
157
+
158
+ result.metrics['revenue.total']?.current.value
159
+ result.metrics.pipeline?.current.kind
160
+
161
+ const metricsRouter = createMetricsRouter({
162
+ registry: metricsRegistry,
163
+ createContext: async (orpcCtx: { db: unknown; viewerId: string }) => ({
164
+ db: orpcCtx.db,
165
+ viewerId: orpcCtx.viewerId,
166
+ }),
167
+ })
168
+ ```
169
+
170
+ ## Define An Engine
171
+
172
+ `createMetricsEngine()` is the main entry point. It owns:
173
+
174
+ - your resolver context type
175
+ - your base filter schema
176
+ - your cache adapter
177
+ - your custom metric kinds
178
+
179
+ ```ts
180
+ const engine = createMetricsEngine<
181
+ { db: DbClient; tenantId: string },
182
+ z.infer<typeof AppFiltersSchema>
183
+ >({
184
+ baseFilters: AppFiltersSchema,
185
+ })
186
+ ```
187
+
188
+ Use the engine methods to define metrics:
189
+
190
+ - `engine.defineKpiMetric(def)`
191
+ - `engine.defineTimeSeriesMetric(def)`
192
+ - `engine.defineDistributionMetric(def)`
193
+ - `engine.defineTableMetric(def)`
194
+ - `engine.defineLeaderboardMetric(def)`
195
+ - `engine.definePivotMetric(def)`
196
+ - `engine.defineMetric(kind, def)` for custom kinds
197
+
198
+ ## Create A Registry
199
+
200
+ The registry is the central typed contract for your app.
201
+
202
+ ```ts
203
+ export const metricsRegistry = engine.createRegistry([
204
+ totalRevenueMetric,
205
+ pipelineFunnelMetric,
206
+ ] as const)
207
+ ```
208
+
209
+ The registry drives:
210
+
211
+ - valid metric keys
212
+ - request filter typing per metric
213
+ - result typing per request
214
+ - ORPC procedures
215
+ - frontend request and dashboard helpers
216
+
217
+ ## Output Types
218
+
219
+ There are two similarly named output concepts:
220
+
221
+ - `MetricOutput` from `metrickit` is the schema-level union of built-in output shapes
222
+ - `MetricOutputFromDef` from `metrickit` gives you the resolved output type for a specific metric definition
223
+
224
+ Use `MetricOutputFromDef` when you want the output type of a concrete metric definition.
225
+
226
+ ## Run Metrics Directly
227
+
228
+ Use `runMetrics()` on the server when you do not need ORPC.
229
+
230
+ ```ts
231
+ const result = await runMetrics({
232
+ registry: metricsRegistry,
233
+ request: {
234
+ metrics: [
235
+ { key: 'revenue.total' },
236
+ { key: 'pipeline.funnel', requestKey: 'pipeline' },
237
+ ],
238
+ },
239
+ createContext: async () => ({ db, viewerId }),
240
+ })
241
+ ```
242
+
243
+ Use `runMetricsStream()` when your consumer wants streamed chunks as metrics resolve.
244
+
245
+ ## ORPC Integration
246
+
247
+ `metrickit/orpc` exposes typed helpers for the common API surface.
248
+
249
+ ```ts
250
+ import { createMetricsRouter } from 'metrickit/orpc'
251
+
252
+ export const metricsRouter = createMetricsRouter({
253
+ registry: metricsRegistry,
254
+ createContext: async (orpcCtx: { db: DbClient; viewerId: string }) => ({
255
+ db: orpcCtx.db,
256
+ viewerId: orpcCtx.viewerId,
257
+ }),
258
+ })
259
+
260
+ const availableMetrics = metricsRouter.getAvailableMetrics({
261
+ db,
262
+ viewerId: 'viewer_1',
263
+ })
264
+
265
+ const result = await metricsRouter.runMetrics(
266
+ {
267
+ metrics: [{ key: 'revenue.total' }],
268
+ },
269
+ { db, viewerId: 'viewer_1' },
270
+ )
271
+ ```
272
+
273
+ ## Caching
274
+
275
+ The engine accepts any `CacheAdapter`. If you already have a Redis-like client, use the built-in adapter:
276
+
277
+ ```ts
278
+ import { redisCacheAdapter } from 'metrickit/cache-redis'
279
+
280
+ const engine = createMetricsEngine({
281
+ cache: redisCacheAdapter(redisClient),
282
+ })
283
+ ```
284
+
285
+ Your Redis client only needs:
286
+
287
+ - `mget(...keys)`
288
+ - `pipeline().setex(...).exec()`
289
+
290
+ ## Frontend Helpers
291
+
292
+ `metrickit/frontend` is intentionally framework-neutral. It gives you typed request builders, stream-state helpers, catalog helpers, and dashboard config utilities that can be wrapped by React, Vue, or another UI layer.
293
+
294
+ ```ts
295
+ import {
296
+ createMetricsStreamState,
297
+ defineHeadline,
298
+ defineMetricRequest,
299
+ defineMetricsDashboard,
300
+ defineMetricsRequest,
301
+ defineWidget,
302
+ getMetricResult,
303
+ } from 'metrickit/frontend'
304
+
305
+ const request = defineMetricsRequest<typeof metricsRegistry>({
306
+ metrics: [
307
+ defineMetricRequest<typeof metricsRegistry, 'revenue.total'>({
308
+ key: 'revenue.total',
309
+ requestKey: 'revenue',
310
+ }),
311
+ ] as const,
312
+ })
313
+
314
+ const revenueResult = getMetricResult(
315
+ {
316
+ metrics: {
317
+ revenue: {
318
+ current: defineKpiOutput({ value: 1200, label: 'Revenue' }),
319
+ previous: undefined,
320
+ supportsTimeRange: true,
321
+ },
322
+ },
323
+ errors: {},
324
+ },
325
+ 'revenue',
326
+ )
327
+
328
+ const dashboard = defineMetricsDashboard<typeof metricsRegistry>({
329
+ title: 'Overview',
330
+ widgets: [
331
+ defineHeadline('Revenue'),
332
+ defineWidget<typeof metricsRegistry, 'revenue.total'>('revenue.total', {
333
+ requestKey: 'revenue',
334
+ layout: { cols: 6 },
335
+ }),
336
+ ] as const,
337
+ })
338
+
339
+ const streamState = createMetricsStreamState(request)
340
+ ```
341
+
342
+ The frontend package includes helpers for:
343
+
344
+ - typed requests and results
345
+ - stream-state handling
346
+ - dashboard config and widget definitions
347
+ - available metric catalog shaping
348
+ - formatting and time labels
349
+ - chart markers and renderer registries
350
+
351
+ ## Advanced Helpers
352
+
353
+ Advanced utility helpers are grouped under `metrickit/helpers` instead of the root package so the primary API stays smaller and easier to learn.
354
+
355
+ ```ts
356
+ import {
357
+ buildTimeRangeWhere,
358
+ mapBucketsToPoints,
359
+ resolveMetricType,
360
+ } from 'metrickit/helpers'
361
+ ```
362
+
363
+ ## Notes
364
+
365
+ - `createRegistry()` is the main typed contract you should export from your app.
366
+ - `requestKey` lets you alias a metric result key while preserving type safety.
367
+ - `runMetrics()` and `runMetricsStream()` validate requests against the registry before executing resolvers.
368
+ - Most consumers only need the engine, registry, runtime helpers, and optional ORPC/frontend entry points.
369
+ - `metrickit/helpers` is the place for more specialized utilities that are not part of the minimal happy path.
370
+
371
+ ## Local Development
372
+
373
+ ```bash
374
+ bun run typecheck
375
+ bun test
376
+ bun run lint
377
+ bun run build
378
+ bun run smoke:pack
379
+ ```
@@ -0,0 +1,10 @@
1
+ import type { CacheAdapter } from './cache.ts';
2
+ export interface RedisLikeClient {
3
+ mget(...keys: string[]): Promise<(string | null)[]>;
4
+ pipeline(): RedisPipeline;
5
+ }
6
+ export interface RedisPipeline {
7
+ setex(key: string, seconds: number, value: string): RedisPipeline;
8
+ exec(): Promise<unknown>;
9
+ }
10
+ export declare function redisCacheAdapter(client: RedisLikeClient): CacheAdapter;
@@ -0,0 +1,24 @@
1
+ // src/cache-redis.ts
2
+ function redisCacheAdapter(client) {
3
+ return {
4
+ async mget(keys) {
5
+ if (keys.length === 0)
6
+ return [];
7
+ return client.mget(...keys);
8
+ },
9
+ async mset(entries) {
10
+ if (entries.length === 0)
11
+ return;
12
+ const pipeline = client.pipeline();
13
+ for (const { key, value, ttl } of entries) {
14
+ if (ttl > 0) {
15
+ pipeline.setex(key, ttl, value);
16
+ }
17
+ }
18
+ await pipeline.exec();
19
+ }
20
+ };
21
+ }
22
+ export {
23
+ redisCacheAdapter
24
+ };
@@ -0,0 +1,5 @@
1
+ type JsonPrimitive = string | number | boolean | null | JsonPrimitive[];
2
+ export declare function stableHash(obj: Record<string, JsonPrimitive>): string;
3
+ export declare function normalizeForCache(obj: Record<string, unknown>): Record<string, JsonPrimitive>;
4
+ export declare function getCacheKey(metricKey: string, filters: Record<string, unknown>, period?: 'current' | 'previous', granularity?: string): string;
5
+ export {};
@@ -0,0 +1,18 @@
1
+ export interface CacheAdapter {
2
+ mget(keys: string[]): Promise<(string | null)[]>;
3
+ mset(entries: {
4
+ key: string;
5
+ value: string;
6
+ ttl: number;
7
+ }[]): Promise<void>;
8
+ }
9
+ export declare const noopCacheAdapter: CacheAdapter;
10
+ interface SafeParseResult<T> {
11
+ success: boolean;
12
+ data?: T;
13
+ }
14
+ interface SafeParser<T> {
15
+ safeParse: (data: unknown) => SafeParseResult<T>;
16
+ }
17
+ export declare function parseCache<T>(cached: string | null, schema: SafeParser<T>): T | null;
18
+ export {};
@@ -0,0 +1,12 @@
1
+ export type MetricCatalogFreshness = 'realtime' | 'nearRealtime' | 'hourly' | 'daily' | 'manual';
2
+ export type MetricCatalogSource = 'prisma' | 'clickhouse' | 'redis' | 'computed';
3
+ export interface MetricCatalogMetadata {
4
+ displayName?: string;
5
+ owner?: string;
6
+ freshness?: MetricCatalogFreshness;
7
+ sources?: MetricCatalogSource[];
8
+ intendedUse?: string;
9
+ drilldownRoute?: string;
10
+ tags?: string[];
11
+ }
12
+ export declare function defineMetricCatalogMetadata<T extends MetricCatalogMetadata>(metadata: T): T;
@@ -0,0 +1,37 @@
1
+ import type { z } from 'zod';
2
+ import type { MetricCatalogMetadata } from './catalog.ts';
3
+ import type { BaseFilters, OutputForKind, OutputKind, OutputSchemaForKind, TimeSeriesOutput } from './schemas/index.ts';
4
+ import type { TimeGranularity } from './schemas/time.ts';
5
+ import type { MetricFilterFieldMetadata } from './filters/types.ts';
6
+ export type MetricFilterFieldMetadataMap<TFilters extends BaseFilters> = Partial<Record<Extract<keyof Omit<TFilters, 'organizationIds' | 'from' | 'to'>, string>, MetricFilterFieldMetadata>>;
7
+ export interface MetricDefinition<TKey extends string, TKind extends string, TFilters extends BaseFilters, TOutput, TContext = unknown, TCatalog extends MetricCatalogMetadata | undefined = MetricCatalogMetadata | undefined> {
8
+ key: TKey;
9
+ kind: TKind;
10
+ outputSchema: z.ZodType<TOutput>;
11
+ description: string;
12
+ allowedRoles?: string[];
13
+ supportsTimeRange: boolean;
14
+ filterSchema: z.ZodType<TFilters>;
15
+ filterFieldMetadata?: MetricFilterFieldMetadataMap<TFilters>;
16
+ catalog?: TCatalog;
17
+ cacheTtl?: number;
18
+ resolve(args: {
19
+ filters: TFilters;
20
+ ctx: TContext & {
21
+ granularity?: TimeGranularity;
22
+ };
23
+ }): Promise<TOutput>;
24
+ }
25
+ export type MetricDefinitionInput<TKey extends string, TKind extends string, TFilters extends BaseFilters, TOutput, TContext = unknown, TCatalog extends MetricCatalogMetadata | undefined = MetricCatalogMetadata | undefined> = Omit<MetricDefinition<TKey, TKind, TFilters, TOutput, TContext, TCatalog>, 'kind' | 'outputSchema'>;
26
+ export declare function defineMetricWithSchema<TKey extends string, TKind extends string, TFilters extends BaseFilters, TSchema extends z.ZodTypeAny, TContext = unknown, TCatalog extends MetricCatalogMetadata | undefined = MetricCatalogMetadata | undefined>(kind: TKind, outputSchema: TSchema, def: MetricDefinitionInput<TKey, TKind, TFilters, z.output<TSchema>, TContext, TCatalog>): MetricDefinition<TKey, TKind, TFilters, z.output<TSchema>, TContext, TCatalog>;
27
+ export declare function defineKpiMetric<TKey extends string, TFilters extends BaseFilters, TContext = unknown, TCatalog extends MetricCatalogMetadata | undefined = MetricCatalogMetadata | undefined>(def: MetricDefinitionInput<TKey, 'kpi', TFilters, OutputForKind<'kpi'>, TContext, TCatalog>): MetricDefinition<TKey, 'kpi', TFilters, OutputForKind<'kpi'>, TContext, TCatalog>;
28
+ export declare function defineTimeSeriesMetric<TKey extends string, TFilters extends BaseFilters, TContext = unknown, TCatalog extends MetricCatalogMetadata | undefined = MetricCatalogMetadata | undefined>(def: MetricDefinitionInput<TKey, 'timeseries', TFilters, TimeSeriesOutput, TContext, TCatalog>): MetricDefinition<TKey, 'timeseries', TFilters, TimeSeriesOutput, TContext, TCatalog>;
29
+ export declare function defineDistributionMetric<TKey extends string, TFilters extends BaseFilters, TContext = unknown, TCatalog extends MetricCatalogMetadata | undefined = MetricCatalogMetadata | undefined>(def: MetricDefinitionInput<TKey, 'distribution', TFilters, OutputForKind<'distribution'>, TContext, TCatalog>): MetricDefinition<TKey, 'distribution', TFilters, OutputForKind<'distribution'>, TContext, TCatalog>;
30
+ export declare function defineTableMetric<TKey extends string, TFilters extends BaseFilters, TContext = unknown, TCatalog extends MetricCatalogMetadata | undefined = MetricCatalogMetadata | undefined>(def: MetricDefinitionInput<TKey, 'table', TFilters, OutputForKind<'table'>, TContext, TCatalog>): MetricDefinition<TKey, 'table', TFilters, OutputForKind<'table'>, TContext, TCatalog>;
31
+ export declare function defineLeaderboardMetric<TKey extends string, TFilters extends BaseFilters, TContext = unknown, TCatalog extends MetricCatalogMetadata | undefined = MetricCatalogMetadata | undefined>(def: MetricDefinitionInput<TKey, 'leaderboard', TFilters, OutputForKind<'leaderboard'>, TContext, TCatalog>): MetricDefinition<TKey, 'leaderboard', TFilters, OutputForKind<'leaderboard'>, TContext, TCatalog>;
32
+ export declare function definePivotMetric<TKey extends string, TFilters extends BaseFilters, TContext = unknown, TCatalog extends MetricCatalogMetadata | undefined = MetricCatalogMetadata | undefined>(def: MetricDefinitionInput<TKey, 'pivot', TFilters, OutputForKind<'pivot'>, TContext, TCatalog>): MetricDefinition<TKey, 'pivot', TFilters, OutputForKind<'pivot'>, TContext, TCatalog>;
33
+ export declare function getOutputSchema<T extends AnyMetricDefinition>(metric: T): T['outputSchema'] | OutputSchemaForKind<Extract<T['kind'], OutputKind>>;
34
+ export declare function validateMetricOutput<T extends AnyMetricDefinition>(metric: T, output: unknown): Awaited<ReturnType<T['resolve']>>;
35
+ export type AnyMetricDefinition = MetricDefinition<string, string, BaseFilters, unknown, unknown, MetricCatalogMetadata | undefined>;
36
+ export type MetricKey<T extends AnyMetricDefinition> = T['key'];
37
+ export type MetricOutput<T extends AnyMetricDefinition> = Awaited<ReturnType<T['resolve']>>;