@ayepi/core 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +89 -0
- package/dist/client/index.cjs +5 -0
- package/dist/client/index.d.cts +2 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.js +2 -0
- package/dist/doer.cjs +110 -0
- package/dist/doer.d.cts +75 -0
- package/dist/doer.d.ts +75 -0
- package/dist/doer.js +106 -0
- package/dist/errors.d.cts +1729 -0
- package/dist/errors.d.ts +1729 -0
- package/dist/index.cjs +2004 -0
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +1968 -0
- package/dist/retry.cjs +135 -0
- package/dist/retry.d.cts +90 -0
- package/dist/retry.d.ts +90 -0
- package/dist/retry.js +129 -0
- package/dist/stats.cjs +0 -0
- package/dist/stats.d.cts +150 -0
- package/dist/stats.d.ts +150 -0
- package/dist/stats.js +0 -0
- package/dist/types.d.cts +54 -0
- package/dist/types.d.ts +54 -0
- package/dist/ws-transport.cjs +1472 -0
- package/dist/ws-transport.js +1383 -0
- package/package.json +110 -0
package/dist/stats.d.ts
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
//#region src/stats.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* # Stats — a tiny, runtime-agnostic metrics primitive
|
|
4
|
+
*
|
|
5
|
+
* A dependency-free way to track named, typed measurements and hand them to whatever the
|
|
6
|
+
* end user already runs — a periodic log, StatsD, Prometheus. Three metric kinds cover
|
|
7
|
+
* the field:
|
|
8
|
+
*
|
|
9
|
+
* - **counter** — a monotonic tally (`inc`): requests served, jobs failed.
|
|
10
|
+
* - **gauge** — a value that moves both ways (`set`/`add`/`max`): in-flight count, a peak.
|
|
11
|
+
* - **summary** — a distribution of observations (`observe`): always count/total/min/max/avg,
|
|
12
|
+
* and — when buckets/quantiles are configured — histogram buckets + approximate
|
|
13
|
+
* percentiles (p50/p95/p99). Histogram-backed, so it's deterministic and bounded-memory.
|
|
14
|
+
*
|
|
15
|
+
* Every metric carries metadata (`name`, `kind`, `description`, `unit`) and is **labelled**
|
|
16
|
+
* (e.g. `{ type: 'email' }`), so one name spans many series. {@link createMetrics} is the
|
|
17
|
+
* registry: create handles, snapshot every series as a flat {@link StatValue} list, and
|
|
18
|
+
* {@link Metrics.subscribe} to **coalesced** change notifications (a burst of mutations
|
|
19
|
+
* yields one batched callback). {@link formatPrometheus} renders a snapshot as Prometheus
|
|
20
|
+
* text exposition.
|
|
21
|
+
*
|
|
22
|
+
* ```ts
|
|
23
|
+
* import { createMetrics, formatPrometheus } from '@ayepi/core'
|
|
24
|
+
*
|
|
25
|
+
* const m = createMetrics({ quantiles: [0.5, 0.95, 0.99] })
|
|
26
|
+
* m.counter('jobs_done', { type: 'email' }).inc()
|
|
27
|
+
* m.summary('job_ms', { type: 'email' }, { unit: 'ms' }).observe(42)
|
|
28
|
+
*
|
|
29
|
+
* setInterval(() => console.log(formatPrometheus(m.list())), 15_000) // scrape/log loop
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @module
|
|
33
|
+
*/
|
|
34
|
+
/** The three metric shapes. */
|
|
35
|
+
type StatKind = 'counter' | 'gauge' | 'summary';
|
|
36
|
+
/** A metric's label set (a series within a metric family). Values are strings, order-insensitive. */
|
|
37
|
+
type Labels = Readonly<Record<string, string>>;
|
|
38
|
+
/** Static metadata describing a metric family (shared across its label series). */
|
|
39
|
+
interface StatMeta {
|
|
40
|
+
/** The metric name (the family key). */
|
|
41
|
+
readonly name: string;
|
|
42
|
+
/** Which kind of metric this is. */
|
|
43
|
+
readonly kind: StatKind;
|
|
44
|
+
/** Human-readable description (exported as Prometheus `# HELP`). */
|
|
45
|
+
readonly description?: string;
|
|
46
|
+
/** Unit of measure, e.g. `'ms'`, `'bytes'`, `'count'` (informational). */
|
|
47
|
+
readonly unit?: string;
|
|
48
|
+
}
|
|
49
|
+
/** One histogram bucket: the cumulative count of observations `<= le` (`le` = upper bound, `Infinity` for the overflow). */
|
|
50
|
+
interface StatBucket {
|
|
51
|
+
readonly le: number;
|
|
52
|
+
readonly count: number;
|
|
53
|
+
}
|
|
54
|
+
/** A summary's distribution snapshot. `quantiles`/`buckets` are present only when configured. */
|
|
55
|
+
interface StatSummary {
|
|
56
|
+
/** Number of observations. */
|
|
57
|
+
readonly count: number;
|
|
58
|
+
/** Sum of all observations. */
|
|
59
|
+
readonly total: number;
|
|
60
|
+
/** Smallest observation (0 when none). */
|
|
61
|
+
readonly min: number;
|
|
62
|
+
/** Largest observation (0 when none). */
|
|
63
|
+
readonly max: number;
|
|
64
|
+
/** Mean (0 when none). */
|
|
65
|
+
readonly avg: number;
|
|
66
|
+
/** Approximate quantiles by probability key, e.g. `{ '0.95': 180 }` — when `quantiles` were configured. */
|
|
67
|
+
readonly quantiles?: Readonly<Record<string, number>>;
|
|
68
|
+
/** Cumulative histogram buckets — when buckets were configured. */
|
|
69
|
+
readonly buckets?: readonly StatBucket[];
|
|
70
|
+
}
|
|
71
|
+
/** A point-in-time snapshot of a single metric series (one name + label set). */
|
|
72
|
+
interface StatValue {
|
|
73
|
+
/** The owning family's metadata. */
|
|
74
|
+
readonly meta: StatMeta;
|
|
75
|
+
/** This series' labels. */
|
|
76
|
+
readonly labels: Labels;
|
|
77
|
+
/** Counter/gauge value; for a summary, its observation `count` (full detail in {@link summary}). */
|
|
78
|
+
readonly value: number;
|
|
79
|
+
/** Present iff `meta.kind === 'summary'`. */
|
|
80
|
+
readonly summary?: StatSummary;
|
|
81
|
+
}
|
|
82
|
+
/** A monotonic tally. */
|
|
83
|
+
interface Counter {
|
|
84
|
+
/** Add `by` (default 1). */
|
|
85
|
+
inc(by?: number): void;
|
|
86
|
+
/** Current total. */
|
|
87
|
+
value(): number;
|
|
88
|
+
}
|
|
89
|
+
/** A value that moves up and down. */
|
|
90
|
+
interface Gauge {
|
|
91
|
+
/** Replace the value. */
|
|
92
|
+
set(v: number): void;
|
|
93
|
+
/** Add `by` (may be negative). */
|
|
94
|
+
add(by: number): void;
|
|
95
|
+
/** Raise to `v` if larger (a running high-water mark). */
|
|
96
|
+
max(v: number): void;
|
|
97
|
+
/** Current value. */
|
|
98
|
+
value(): number;
|
|
99
|
+
}
|
|
100
|
+
/** A distribution of observations. */
|
|
101
|
+
interface Summary {
|
|
102
|
+
/** Record one observation. */
|
|
103
|
+
observe(v: number): void;
|
|
104
|
+
/** Current distribution snapshot. */
|
|
105
|
+
snapshot(): StatSummary;
|
|
106
|
+
}
|
|
107
|
+
/** Options for {@link createMetrics}. */
|
|
108
|
+
interface MetricsOptions {
|
|
109
|
+
/**
|
|
110
|
+
* Probabilities (0–1) to estimate for every summary, e.g. `[0.5, 0.95, 0.99]`. Enables
|
|
111
|
+
* histogram bucketing (default {@link DEFAULT_BUCKETS} unless `buckets` is given) and fills
|
|
112
|
+
* {@link StatSummary.quantiles}. Omit for count/total/min/max/avg only (no per-observation cost).
|
|
113
|
+
*/
|
|
114
|
+
readonly quantiles?: readonly number[];
|
|
115
|
+
/** Histogram bucket upper bounds for summaries (ascending). Defaults to {@link DEFAULT_BUCKETS} when `quantiles` is set. */
|
|
116
|
+
readonly buckets?: readonly number[];
|
|
117
|
+
/**
|
|
118
|
+
* Schedules the coalesced flush of change notifications. Default batches via `queueMicrotask`
|
|
119
|
+
* (one callback per synchronous burst). Inject `(fn) => fn()` for synchronous delivery, or a
|
|
120
|
+
* manual collector in tests.
|
|
121
|
+
*/
|
|
122
|
+
readonly schedule?: (flush: () => void) => void;
|
|
123
|
+
}
|
|
124
|
+
/** The metrics registry returned by {@link createMetrics}. */
|
|
125
|
+
interface Metrics {
|
|
126
|
+
/** Get-or-create a {@link Counter} series. */
|
|
127
|
+
counter(name: string, labels?: Labels, meta?: Omit<StatMeta, 'name' | 'kind'>): Counter;
|
|
128
|
+
/** Get-or-create a {@link Gauge} series. */
|
|
129
|
+
gauge(name: string, labels?: Labels, meta?: Omit<StatMeta, 'name' | 'kind'>): Gauge;
|
|
130
|
+
/** Get-or-create a {@link Summary} series. */
|
|
131
|
+
summary(name: string, labels?: Labels, meta?: Omit<StatMeta, 'name' | 'kind'>): Summary;
|
|
132
|
+
/** Snapshot every series as a flat list (one {@link StatValue} per name + label set). */
|
|
133
|
+
list(): StatValue[];
|
|
134
|
+
/** Snapshot one series, or `undefined` if it was never created. */
|
|
135
|
+
get(name: string, labels?: Labels): StatValue | undefined;
|
|
136
|
+
/** Subscribe to **coalesced** change notifications; the listener gets the batch of changed series. Returns an unsubscribe fn. */
|
|
137
|
+
subscribe(listener: (changed: readonly StatValue[]) => void): () => void;
|
|
138
|
+
}
|
|
139
|
+
/** Default histogram bucket upper bounds (ms-oriented), used when `quantiles` is set without explicit `buckets`. */
|
|
140
|
+
declare const DEFAULT_BUCKETS: readonly number[];
|
|
141
|
+
/** Create a metrics registry. */
|
|
142
|
+
declare function createMetrics(opts?: MetricsOptions): Metrics;
|
|
143
|
+
/**
|
|
144
|
+
* Render a {@link Metrics.list} snapshot as Prometheus text exposition format. Counters and gauges
|
|
145
|
+
* map directly; summaries are emitted as **histograms** (`_bucket`/`_count`/`_sum`) when buckets are
|
|
146
|
+
* present, else as bare `_count`/`_sum`. Names are sanitized to valid Prometheus identifiers.
|
|
147
|
+
*/
|
|
148
|
+
declare function formatPrometheus(stats: readonly StatValue[]): string;
|
|
149
|
+
//#endregion
|
|
150
|
+
export { Counter, DEFAULT_BUCKETS, Gauge, Labels, Metrics, MetricsOptions, StatBucket, StatKind, StatMeta, StatSummary, StatValue, Summary, createMetrics, formatPrometheus };
|
package/dist/stats.js
ADDED
|
Binary file
|
package/dist/types.d.cts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
//#region src/types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* # Type utilities
|
|
4
|
+
*
|
|
5
|
+
* Small, dependency-free type-level helpers used across the library. None of
|
|
6
|
+
* these emit runtime code — they exist purely to make the public generic
|
|
7
|
+
* surface infer precisely without leaking `any`/`unknown` to consumers.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Flatten an intersection (`A & B & …`) into a single object literal so editor
|
|
13
|
+
* tooltips and `Equal<>` comparisons see one clean shape instead of a chain of
|
|
14
|
+
* intersections.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* type Messy = { a: 1 } & { b: 2 }
|
|
19
|
+
* type Clean = Simplify<Messy> // { a: 1; b: 2 }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
type Simplify<T> = { [K in keyof T]: T[K] } & {};
|
|
23
|
+
/** A value that may be returned either synchronously or as a `Promise`. */
|
|
24
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
25
|
+
/**
|
|
26
|
+
* The empty object type. Used as the identity element when merging contributed
|
|
27
|
+
* shapes (middleware context, path params, etc.) so an absent contribution adds
|
|
28
|
+
* nothing rather than widening the result.
|
|
29
|
+
*/
|
|
30
|
+
type EmptyObject = {};
|
|
31
|
+
/**
|
|
32
|
+
* Convert a union `A | B | C` into the intersection `A & B & C`.
|
|
33
|
+
*
|
|
34
|
+
* Drives middleware-context merging: each middleware contributes a shape, and
|
|
35
|
+
* the handler sees the intersection of every contribution in its chain.
|
|
36
|
+
*/
|
|
37
|
+
type UnionToIntersection<U> = (U extends unknown ? (x: U) => void : never) extends ((x: infer I) => void) ? I : never;
|
|
38
|
+
/** Distribute `keyof` across a union, yielding the union of every member's keys. */
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Safe indexed access: resolves to `T[K]` when `K` is a key of `T`, otherwise
|
|
42
|
+
* `undefined`. Lets optional config properties be read without first proving
|
|
43
|
+
* they exist.
|
|
44
|
+
*/
|
|
45
|
+
type Get<T, K extends string> = K extends keyof T ? T[K] : undefined;
|
|
46
|
+
/**
|
|
47
|
+
* A JSON-shaped value — the closed set of things the OpenAPI/AsyncAPI doc
|
|
48
|
+
* generators produce and accept in their patch callbacks.
|
|
49
|
+
*/
|
|
50
|
+
type Json = string | number | boolean | null | Json[] | {
|
|
51
|
+
[k: string]: Json;
|
|
52
|
+
};
|
|
53
|
+
//#endregion
|
|
54
|
+
export { Simplify as a, MaybePromise as i, Get as n, UnionToIntersection as o, Json as r, EmptyObject as t };
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
//#region src/types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* # Type utilities
|
|
4
|
+
*
|
|
5
|
+
* Small, dependency-free type-level helpers used across the library. None of
|
|
6
|
+
* these emit runtime code — they exist purely to make the public generic
|
|
7
|
+
* surface infer precisely without leaking `any`/`unknown` to consumers.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Flatten an intersection (`A & B & …`) into a single object literal so editor
|
|
13
|
+
* tooltips and `Equal<>` comparisons see one clean shape instead of a chain of
|
|
14
|
+
* intersections.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* type Messy = { a: 1 } & { b: 2 }
|
|
19
|
+
* type Clean = Simplify<Messy> // { a: 1; b: 2 }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
type Simplify<T> = { [K in keyof T]: T[K] } & {};
|
|
23
|
+
/** A value that may be returned either synchronously or as a `Promise`. */
|
|
24
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
25
|
+
/**
|
|
26
|
+
* The empty object type. Used as the identity element when merging contributed
|
|
27
|
+
* shapes (middleware context, path params, etc.) so an absent contribution adds
|
|
28
|
+
* nothing rather than widening the result.
|
|
29
|
+
*/
|
|
30
|
+
type EmptyObject = {};
|
|
31
|
+
/**
|
|
32
|
+
* Convert a union `A | B | C` into the intersection `A & B & C`.
|
|
33
|
+
*
|
|
34
|
+
* Drives middleware-context merging: each middleware contributes a shape, and
|
|
35
|
+
* the handler sees the intersection of every contribution in its chain.
|
|
36
|
+
*/
|
|
37
|
+
type UnionToIntersection<U> = (U extends unknown ? (x: U) => void : never) extends ((x: infer I) => void) ? I : never;
|
|
38
|
+
/** Distribute `keyof` across a union, yielding the union of every member's keys. */
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Safe indexed access: resolves to `T[K]` when `K` is a key of `T`, otherwise
|
|
42
|
+
* `undefined`. Lets optional config properties be read without first proving
|
|
43
|
+
* they exist.
|
|
44
|
+
*/
|
|
45
|
+
type Get<T, K extends string> = K extends keyof T ? T[K] : undefined;
|
|
46
|
+
/**
|
|
47
|
+
* A JSON-shaped value — the closed set of things the OpenAPI/AsyncAPI doc
|
|
48
|
+
* generators produce and accept in their patch callbacks.
|
|
49
|
+
*/
|
|
50
|
+
type Json = string | number | boolean | null | Json[] | {
|
|
51
|
+
[k: string]: Json;
|
|
52
|
+
};
|
|
53
|
+
//#endregion
|
|
54
|
+
export { Simplify as a, MaybePromise as i, Get as n, UnionToIntersection as o, Json as r, EmptyObject as t };
|