UNPKG

@upstash/core-analytics

Version:

<div align="center"> <h1 align="center">@upstash/core-analytics</h1> <h5>Serverless Analytics for Redis</h5> </div>

113 lines (109 loc) 4.32 kB
import { Redis } from '@upstash/redis'; type Event = { time?: number; [key: string]: string | number | boolean | undefined; }; type Window = `${number}${"s" | "m" | "h" | "d"}`; type AnalyticsConfig = { redis: Redis; /** * Configure the bucket size for analytics. All events inside the window will be stored inside * the same bucket. This reduces the number of keys that need to be scanned when aggregating * and reduces your cost. * * Must be either a string in the format of `1s`, `2m`, `3h`, `4d` or a number of milliseconds. */ window: Window | number; prefix?: string; /** * Configure the retention period for analytics. All events older than the retention period will * be deleted. This reduces the number of keys that need to be scanned when aggregating. * * Can either be a string in the format of `1s`, `2m`, `3h`, `4d` or a number of milliseconds. * 0, negative or undefined means that the retention is disabled. * * @default Disabled * * Buckets are evicted when they are read, not when they are written. This is much cheaper since * it only requires a single command to ingest data. */ retention?: Window | number; }; interface AggregateTime { time: number; } interface AggregateGeneric { [someFieldName: string]: { [someFieldValue: string]: number; }; } type Aggregate = AggregateTime & AggregateGeneric; type RawSuccessResponse = 1 | null; type SuccessResponse = RawSuccessResponse | string; declare class Analytics { private readonly redis; private readonly prefix; private readonly bucketSize; constructor(config: AnalyticsConfig); private validateTableName; /** * Parses the window string into a number of milliseconds */ private parseWindow; getBucket(time?: number): number; /** * Ingest a new event * @param table * @param event */ ingest(table: string, ...events: Event[]): Promise<void>; protected formatBucketAggregate(rawAggregate: [SuccessResponse, number][], groupBy: string, bucket: number): Aggregate; aggregateBucket(table: string, groupBy: string, timestamp?: number): Promise<Aggregate>; aggregateBuckets(table: string, groupBy: string, bucketCount: number, timestamp?: number): Promise<Aggregate[]>; aggregateBucketsWithPipeline(table: string, groupBy: string, bucketCount: number, timestamp?: number, maxPipelineSize?: number): Promise<Aggregate[]>; getAllowedBlocked(table: string, timestampCount: number, timestamp?: number): Promise<Record<string, { success: number; blocked: number; }>>; /** * Fetches the most allowed & blocked and denied items. * * @param table Ratelimit prefix to search for analytics * @param timestampCount Number of timestamps (24 for a day and 24 * 7 for a week) * @param itemCount Number of items to fetch from each category. If set to 30, * 30 items will be fetched from each category. 90 items will be * returned in total if there are enough items in each category. * @param timestamp Most recent bucket timestamp to read from * @param checkAtMost Early finish parameter. Imagine that itemCount is set to 30. * If checkAtMost is set to 100, script will stop after checking * 100 items even if there aren't 90 items yet. * Set to `itemCount * 5` by default. * @returns most allowed & blocked and denied items */ getMostAllowedBlocked(table: string, timestampCount: number, itemCount: number, timestamp?: number, checkAtMost?: number): Promise<{ allowed: { identifier: string; count: number; }[]; ratelimited: { identifier: string; count: number; }[]; denied: { identifier: string; count: number; }[]; }>; /** * convert ["a", 1, ...] to [{identifier: 1, count: 1}, ...] * @param array */ protected toDicts(array: [string, { identifier: string; success: boolean; }][]): { identifier: string; count: number; }[]; } export { type Aggregate, Analytics };