honk-me 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/CHANGELOG.md +24 -0
- package/LICENSE +21 -0
- package/README.md +224 -0
- package/dist/cjs/client.d.ts +58 -0
- package/dist/cjs/client.js +334 -0
- package/dist/cjs/errors.d.ts +84 -0
- package/dist/cjs/errors.js +108 -0
- package/dist/cjs/index.d.ts +5 -0
- package/dist/cjs/index.js +29 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/types.d.ts +138 -0
- package/dist/cjs/types.js +53 -0
- package/dist/cjs/uuid.d.ts +5 -0
- package/dist/cjs/uuid.js +40 -0
- package/dist/cjs/validate.d.ts +28 -0
- package/dist/cjs/validate.js +272 -0
- package/dist/cjs/version.d.ts +1 -0
- package/dist/cjs/version.js +6 -0
- package/dist/esm/client.d.ts +58 -0
- package/dist/esm/client.js +329 -0
- package/dist/esm/errors.d.ts +84 -0
- package/dist/esm/errors.js +97 -0
- package/dist/esm/index.d.ts +5 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/types.d.ts +138 -0
- package/dist/esm/types.js +49 -0
- package/dist/esm/uuid.d.ts +5 -0
- package/dist/esm/uuid.js +37 -0
- package/dist/esm/validate.d.ts +28 -0
- package/dist/esm/validate.js +265 -0
- package/dist/esm/version.d.ts +1 -0
- package/dist/esm/version.js +3 -0
- package/package.json +68 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
export type ErrorKind = 'validation' | 'auth' | 'quota' | 'conflict' | 'network' | 'timeout' | 'server' | 'http';
|
|
2
|
+
/** One invalid field, as reported by the server (`error.fields[]`) or by local validation. */
|
|
3
|
+
export interface FieldError {
|
|
4
|
+
/** Wire name, e.g. `group_key`, `metadata.region`, `Idempotency-Key`, `body`. */
|
|
5
|
+
field: string;
|
|
6
|
+
/** `required`, `too_long`, `too_short`, `invalid_enum`, `invalid_format`, `out_of_range`, `not_allowed`, `requires_group_key`, … */
|
|
7
|
+
code: string;
|
|
8
|
+
message?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface HonkErrorInit {
|
|
11
|
+
status?: number;
|
|
12
|
+
code?: string;
|
|
13
|
+
requestId?: string;
|
|
14
|
+
idempotencyKey?: string;
|
|
15
|
+
attempts?: number;
|
|
16
|
+
retryAfter?: number;
|
|
17
|
+
fields?: FieldError[];
|
|
18
|
+
body?: unknown;
|
|
19
|
+
cause?: unknown;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Base class of every error thrown by `send()`. Check `kind` (or `instanceof`) to decide what to do:
|
|
23
|
+
* `retryable` errors can be retried later with the same `idempotencyKey` without creating duplicates.
|
|
24
|
+
*/
|
|
25
|
+
export declare class HonkError extends Error {
|
|
26
|
+
readonly kind: ErrorKind;
|
|
27
|
+
/** HTTP status, when the server answered. */
|
|
28
|
+
readonly status?: number;
|
|
29
|
+
/** API error code (`invalid_key`, `quota_exceeded`, …) or `network_error` / `timeout`. */
|
|
30
|
+
readonly code?: string;
|
|
31
|
+
/** Server request id (`req_…`), useful in bug reports. */
|
|
32
|
+
readonly requestId?: string;
|
|
33
|
+
/** The Idempotency-Key that was used. Retry later with the same key to stay duplicate-free. */
|
|
34
|
+
readonly idempotencyKey?: string;
|
|
35
|
+
/** Number of HTTP attempts made (0 when the message was rejected locally). */
|
|
36
|
+
readonly attempts: number;
|
|
37
|
+
/** Seconds the server asked to wait (`Retry-After`), when present. */
|
|
38
|
+
readonly retryAfter?: number;
|
|
39
|
+
/** Parsed error body, when the server answered with JSON. */
|
|
40
|
+
readonly body?: unknown;
|
|
41
|
+
constructor(message: string, init?: HonkErrorInit);
|
|
42
|
+
/** True when sending the same event again later (same idempotency key) may succeed. */
|
|
43
|
+
get retryable(): boolean;
|
|
44
|
+
}
|
|
45
|
+
/** The message is invalid: rejected locally before sending, or by the server (400, 413, 415, 422). Fix the message. */
|
|
46
|
+
export declare class HonkValidationError extends HonkError {
|
|
47
|
+
readonly kind: 'validation';
|
|
48
|
+
readonly fields: FieldError[];
|
|
49
|
+
/** True when the SDK rejected the message before any request was made. */
|
|
50
|
+
readonly local: boolean;
|
|
51
|
+
constructor(message: string, init?: HonkErrorInit & {
|
|
52
|
+
local?: boolean;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/** 401/403: invalid or revoked key, `priority_not_allowed` (urgent without allow_urgent), suspended project/workspace. */
|
|
56
|
+
export declare class HonkAuthError extends HonkError {
|
|
57
|
+
readonly kind: 'auth';
|
|
58
|
+
constructor(message: string, init?: HonkErrorInit);
|
|
59
|
+
}
|
|
60
|
+
/** 429: `quota_exceeded` (daily messages_per_day, until UTC midnight) or `rate_limited`, after retries. See `retryAfter`. */
|
|
61
|
+
export declare class HonkQuotaError extends HonkError {
|
|
62
|
+
readonly kind: 'quota';
|
|
63
|
+
constructor(message: string, init?: HonkErrorInit);
|
|
64
|
+
}
|
|
65
|
+
/** 409 `idempotency_conflict`: this idempotency key was already used with a different payload in the last 24 h. */
|
|
66
|
+
export declare class HonkConflictError extends HonkError {
|
|
67
|
+
readonly kind: 'conflict';
|
|
68
|
+
constructor(message: string, init?: HonkErrorInit);
|
|
69
|
+
}
|
|
70
|
+
/** The server could not be reached (or the connection broke) on every attempt until the deadline. */
|
|
71
|
+
export declare class HonkNetworkError extends HonkError {
|
|
72
|
+
readonly kind: 'network' | 'timeout';
|
|
73
|
+
constructor(message: string, init?: HonkErrorInit);
|
|
74
|
+
}
|
|
75
|
+
/** An attempt timed out and no later attempt succeeded before the deadline. The event may or may not have been stored. */
|
|
76
|
+
export declare class HonkTimeoutError extends HonkNetworkError {
|
|
77
|
+
readonly kind: 'timeout';
|
|
78
|
+
constructor(message: string, init?: HonkErrorInit);
|
|
79
|
+
}
|
|
80
|
+
/** 5xx on every attempt until the deadline (e.g. `503 unavailable`). */
|
|
81
|
+
export declare class HonkServerError extends HonkError {
|
|
82
|
+
readonly kind: 'server';
|
|
83
|
+
constructor(message: string, init?: HonkErrorInit);
|
|
84
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base class of every error thrown by `send()`. Check `kind` (or `instanceof`) to decide what to do:
|
|
3
|
+
* `retryable` errors can be retried later with the same `idempotencyKey` without creating duplicates.
|
|
4
|
+
*/
|
|
5
|
+
export class HonkError extends Error {
|
|
6
|
+
kind = 'http';
|
|
7
|
+
/** HTTP status, when the server answered. */
|
|
8
|
+
status;
|
|
9
|
+
/** API error code (`invalid_key`, `quota_exceeded`, …) or `network_error` / `timeout`. */
|
|
10
|
+
code;
|
|
11
|
+
/** Server request id (`req_…`), useful in bug reports. */
|
|
12
|
+
requestId;
|
|
13
|
+
/** The Idempotency-Key that was used. Retry later with the same key to stay duplicate-free. */
|
|
14
|
+
idempotencyKey;
|
|
15
|
+
/** Number of HTTP attempts made (0 when the message was rejected locally). */
|
|
16
|
+
attempts;
|
|
17
|
+
/** Seconds the server asked to wait (`Retry-After`), when present. */
|
|
18
|
+
retryAfter;
|
|
19
|
+
/** Parsed error body, when the server answered with JSON. */
|
|
20
|
+
body;
|
|
21
|
+
constructor(message, init = {}) {
|
|
22
|
+
super(message, init.cause === undefined ? undefined : { cause: init.cause });
|
|
23
|
+
this.name = 'HonkError';
|
|
24
|
+
this.status = init.status;
|
|
25
|
+
this.code = init.code;
|
|
26
|
+
this.requestId = init.requestId;
|
|
27
|
+
this.idempotencyKey = init.idempotencyKey;
|
|
28
|
+
this.attempts = init.attempts ?? 0;
|
|
29
|
+
this.retryAfter = init.retryAfter;
|
|
30
|
+
this.body = init.body;
|
|
31
|
+
}
|
|
32
|
+
/** True when sending the same event again later (same idempotency key) may succeed. */
|
|
33
|
+
get retryable() {
|
|
34
|
+
return this.kind === 'network' || this.kind === 'timeout' || this.kind === 'server' || this.kind === 'quota';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/** The message is invalid: rejected locally before sending, or by the server (400, 413, 415, 422). Fix the message. */
|
|
38
|
+
export class HonkValidationError extends HonkError {
|
|
39
|
+
kind = 'validation';
|
|
40
|
+
fields;
|
|
41
|
+
/** True when the SDK rejected the message before any request was made. */
|
|
42
|
+
local;
|
|
43
|
+
constructor(message, init = {}) {
|
|
44
|
+
super(message, init);
|
|
45
|
+
this.name = 'HonkValidationError';
|
|
46
|
+
this.fields = init.fields ?? [];
|
|
47
|
+
this.local = init.local ?? false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/** 401/403: invalid or revoked key, `priority_not_allowed` (urgent without allow_urgent), suspended project/workspace. */
|
|
51
|
+
export class HonkAuthError extends HonkError {
|
|
52
|
+
kind = 'auth';
|
|
53
|
+
constructor(message, init = {}) {
|
|
54
|
+
super(message, init);
|
|
55
|
+
this.name = 'HonkAuthError';
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/** 429: `quota_exceeded` (daily messages_per_day, until UTC midnight) or `rate_limited`, after retries. See `retryAfter`. */
|
|
59
|
+
export class HonkQuotaError extends HonkError {
|
|
60
|
+
kind = 'quota';
|
|
61
|
+
constructor(message, init = {}) {
|
|
62
|
+
super(message, init);
|
|
63
|
+
this.name = 'HonkQuotaError';
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/** 409 `idempotency_conflict`: this idempotency key was already used with a different payload in the last 24 h. */
|
|
67
|
+
export class HonkConflictError extends HonkError {
|
|
68
|
+
kind = 'conflict';
|
|
69
|
+
constructor(message, init = {}) {
|
|
70
|
+
super(message, init);
|
|
71
|
+
this.name = 'HonkConflictError';
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/** The server could not be reached (or the connection broke) on every attempt until the deadline. */
|
|
75
|
+
export class HonkNetworkError extends HonkError {
|
|
76
|
+
kind = 'network';
|
|
77
|
+
constructor(message, init = {}) {
|
|
78
|
+
super(message, init);
|
|
79
|
+
this.name = 'HonkNetworkError';
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/** An attempt timed out and no later attempt succeeded before the deadline. The event may or may not have been stored. */
|
|
83
|
+
export class HonkTimeoutError extends HonkNetworkError {
|
|
84
|
+
kind = 'timeout';
|
|
85
|
+
constructor(message, init = {}) {
|
|
86
|
+
super(message, init);
|
|
87
|
+
this.name = 'HonkTimeoutError';
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/** 5xx on every attempt until the deadline (e.g. `503 unavailable`). */
|
|
91
|
+
export class HonkServerError extends HonkError {
|
|
92
|
+
kind = 'server';
|
|
93
|
+
constructor(message, init = {}) {
|
|
94
|
+
super(message, init);
|
|
95
|
+
this.name = 'HonkServerError';
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { Honk, VERSION, parseRetryAfter } from './client.js';
|
|
2
|
+
export { HonkError, HonkValidationError, HonkAuthError, HonkQuotaError, HonkConflictError, HonkNetworkError, HonkTimeoutError, HonkServerError, type ErrorKind, type FieldError, } from './errors.js';
|
|
3
|
+
export { buildBody, LIMITS } from './validate.js';
|
|
4
|
+
export { uuidv7 } from './uuid.js';
|
|
5
|
+
export { Severity, SEVERITY_ALIASES, normalizeSeverity, SEVERITIES, PRIORITIES, EVENT_TYPES, CATEGORIES, type SeverityAlias, type SeverityInput, type Priority, type EventType, type Category, type MetadataValue, type Message, type Defaults, type HonkOptions, type SendOptions, type HelperOptions, type SendResult, } from './types.js';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { Honk, VERSION, parseRetryAfter } from './client.js';
|
|
2
|
+
export { HonkError, HonkValidationError, HonkAuthError, HonkQuotaError, HonkConflictError, HonkNetworkError, HonkTimeoutError, HonkServerError, } from './errors.js';
|
|
3
|
+
export { buildBody, LIMITS } from './validate.js';
|
|
4
|
+
export { uuidv7 } from './uuid.js';
|
|
5
|
+
export { Severity, SEVERITY_ALIASES, normalizeSeverity, SEVERITIES, PRIORITIES, EVENT_TYPES, CATEGORIES, } from './types.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "type": "module" }
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical severity, lowest to highest. `error` and `critical` raise the effective priority to
|
|
3
|
+
* at least `high`. Inputs also accept the horn aliases of the Honk scale ({@link SeverityAlias}).
|
|
4
|
+
*/
|
|
5
|
+
export type Severity = 'info' | 'success' | 'warning' | 'error' | 'critical';
|
|
6
|
+
/** The Honk scale: light (info), beep (success), loud (warning), long (error), blast (critical). */
|
|
7
|
+
export type SeverityAlias = 'light' | 'beep' | 'loud' | 'long' | 'blast';
|
|
8
|
+
/** Any accepted spelling of a severity: canonical or horn alias, lower, Capitalized or UPPER case. */
|
|
9
|
+
export type SeverityInput = Severity | SeverityAlias | Capitalize<Severity | SeverityAlias> | Uppercase<Severity | SeverityAlias>;
|
|
10
|
+
/**
|
|
11
|
+
* Severity constants. The horn names are aliases of the canonical values:
|
|
12
|
+
* `Severity.Loud === Severity.Warning === 'warning'`.
|
|
13
|
+
*/
|
|
14
|
+
export declare const Severity: {
|
|
15
|
+
readonly Light: 'info';
|
|
16
|
+
readonly Beep: 'success';
|
|
17
|
+
readonly Loud: 'warning';
|
|
18
|
+
readonly Long: 'error';
|
|
19
|
+
readonly Blast: 'critical';
|
|
20
|
+
readonly Info: 'info';
|
|
21
|
+
readonly Success: 'success';
|
|
22
|
+
readonly Warning: 'warning';
|
|
23
|
+
readonly Error: 'error';
|
|
24
|
+
readonly Critical: 'critical';
|
|
25
|
+
};
|
|
26
|
+
/** Horn alias → canonical severity. */
|
|
27
|
+
export declare const SEVERITY_ALIASES: Readonly<Record<SeverityAlias, Severity>>;
|
|
28
|
+
/**
|
|
29
|
+
* Returns the canonical severity for a canonical value or horn alias (case-insensitive), or
|
|
30
|
+
* undefined when it is neither: `normalizeSeverity('LOUD') === 'warning'`.
|
|
31
|
+
*/
|
|
32
|
+
export declare function normalizeSeverity(value: string): Severity | undefined;
|
|
33
|
+
/** Declared priority. `urgent` needs an ingestion key with `allow_urgent`. */
|
|
34
|
+
export type Priority = 'low' | 'normal' | 'high' | 'urgent';
|
|
35
|
+
/** `problem` opens an incident for its group; `recovery` closes it (both need `groupKey`). */
|
|
36
|
+
export type EventType = 'event' | 'problem' | 'recovery';
|
|
37
|
+
/** Category taxonomy v1. */
|
|
38
|
+
export type Category = 'infrastructure' | 'security' | 'backups' | 'deployments' | 'payments' | 'customers' | 'sales' | 'automation' | 'personal' | 'other';
|
|
39
|
+
export declare const SEVERITIES: readonly Severity[];
|
|
40
|
+
export declare const PRIORITIES: readonly Priority[];
|
|
41
|
+
export declare const EVENT_TYPES: readonly EventType[];
|
|
42
|
+
export declare const CATEGORIES: readonly Category[];
|
|
43
|
+
export type MetadataValue = string | number | boolean;
|
|
44
|
+
/**
|
|
45
|
+
* One event for `POST /v1/messages`. Only `message` is required. Fields are camelCase here and
|
|
46
|
+
* sent as the snake_case names of the API (`groupKey` → `group_key`). Empty optional strings
|
|
47
|
+
* and `null`/`undefined` are omitted.
|
|
48
|
+
*/
|
|
49
|
+
export interface Message {
|
|
50
|
+
/** Plain text, 1–8192 bytes of UTF-8. Line breaks and tabs are allowed. */
|
|
51
|
+
message: string;
|
|
52
|
+
/** ≤ 160 characters, one line. Defaults to the first line of `message`. */
|
|
53
|
+
title?: string | null;
|
|
54
|
+
/**
|
|
55
|
+
* Default `light` (info). Horn names or canonical values, case-insensitive: `light`/`info`,
|
|
56
|
+
* `beep`/`success`, `loud`/`warning`, `long`/`error`, `blast`/`critical`. Sent canonical.
|
|
57
|
+
*/
|
|
58
|
+
severity?: SeverityInput | null;
|
|
59
|
+
/** Default `normal`. */
|
|
60
|
+
priority?: Priority | null;
|
|
61
|
+
category?: Category | null;
|
|
62
|
+
/** ≤ 64 characters. Default `api` (or the client's `defaults.source`). */
|
|
63
|
+
source?: string | null;
|
|
64
|
+
/** ≤ 32 characters. Default `default` (or the client's `defaults.environment`). */
|
|
65
|
+
environment?: string | null;
|
|
66
|
+
/** ≤ 64 characters. Default `general` (or the client's `defaults.channel`). */
|
|
67
|
+
channel?: string | null;
|
|
68
|
+
/**
|
|
69
|
+
* ≤ 128 characters. Messages with the same key (per environment, source and channel) form one
|
|
70
|
+
* group: one push, then calm updates. Use one key per customer request (`requests/<id>`), a
|
|
71
|
+
* shared key only for repeats of the same problem.
|
|
72
|
+
*/
|
|
73
|
+
groupKey?: string | null;
|
|
74
|
+
/** Default `event`. `recovery` requires `groupKey`. */
|
|
75
|
+
eventType?: EventType | null;
|
|
76
|
+
/** When it happened at the source (informational). A Date or an RFC 3339 string. */
|
|
77
|
+
occurredAt?: Date | string | null;
|
|
78
|
+
/** HTTPS link shown as "Open link". No credentials. ≤ 2048 bytes. */
|
|
79
|
+
url?: string | null;
|
|
80
|
+
/** HTTPS image fetched by the server after ingestion. No credentials or fragment. ≤ 2048 bytes. */
|
|
81
|
+
imageUrl?: string | null;
|
|
82
|
+
/** ≤ 16 keys matching `[A-Za-z0-9_.-]{1,64}`; values are strings (≤ 512 chars), numbers or booleans. */
|
|
83
|
+
metadata?: Record<string, MetadataValue> | null;
|
|
84
|
+
/** Push lifetime, 60–86400 seconds. Default 3600. */
|
|
85
|
+
ttlSeconds?: number | null;
|
|
86
|
+
/** Monotonic counter per source stream (0 … 2^53-1) for problem/recovery ordering. Requires `groupKey`. */
|
|
87
|
+
sourceSequence?: number | null;
|
|
88
|
+
}
|
|
89
|
+
/** Values applied when a message leaves the field unset. */
|
|
90
|
+
export interface Defaults {
|
|
91
|
+
source?: string | null;
|
|
92
|
+
environment?: string | null;
|
|
93
|
+
channel?: string | null;
|
|
94
|
+
}
|
|
95
|
+
export interface HonkOptions {
|
|
96
|
+
/** Base URL of your Honk server, e.g. `https://honk.example.com`. */
|
|
97
|
+
url: string;
|
|
98
|
+
/** Project ingestion key `honk_…`. Server-side only: never ship it to a browser. */
|
|
99
|
+
key: string;
|
|
100
|
+
/** Timeout of one HTTP attempt. Default 5000 ms. */
|
|
101
|
+
timeoutMs?: number;
|
|
102
|
+
/** Retries after the first attempt (network errors, 429 and 5xx only). Default 4. */
|
|
103
|
+
retries?: number;
|
|
104
|
+
/** Total time budget for `send()`, waits included. Default 30000 ms. */
|
|
105
|
+
deadlineMs?: number;
|
|
106
|
+
/** Applied to every message that does not set these fields. */
|
|
107
|
+
defaults?: Defaults;
|
|
108
|
+
/** Validate messages locally before sending. Default `true`. The server always validates. */
|
|
109
|
+
validate?: boolean;
|
|
110
|
+
/** Exponential backoff with full jitter: attempt n waits random(0, min(maxMs, baseMs·2ⁿ)). Default 500 / 8000 ms. */
|
|
111
|
+
backoff?: {
|
|
112
|
+
baseMs?: number;
|
|
113
|
+
maxMs?: number;
|
|
114
|
+
};
|
|
115
|
+
/** Custom fetch (proxies, instrumentation). Default: the global `fetch`. */
|
|
116
|
+
fetch?: typeof fetch;
|
|
117
|
+
/** Appended to the User-Agent header. */
|
|
118
|
+
userAgent?: string;
|
|
119
|
+
}
|
|
120
|
+
export interface SendOptions {
|
|
121
|
+
/**
|
|
122
|
+
* Stable key for this event (1–128 printable ASCII characters), e.g. `request-4812`. Reused on
|
|
123
|
+
* every retry. Default: a new UUIDv7 per `send()` call.
|
|
124
|
+
*/
|
|
125
|
+
idempotencyKey?: string;
|
|
126
|
+
/** Cancels the call (including retries and waits). */
|
|
127
|
+
signal?: AbortSignal;
|
|
128
|
+
}
|
|
129
|
+
/** Message fields and send options together, for the helper methods. */
|
|
130
|
+
export type HelperOptions = Partial<Omit<Message, 'message' | 'title'>> & SendOptions;
|
|
131
|
+
export interface SendResult {
|
|
132
|
+
/** Message id (`msg_…`). The original id when `duplicate` is true. */
|
|
133
|
+
id: string;
|
|
134
|
+
/** True when this idempotency key was already accepted with the same payload (within 24 h). */
|
|
135
|
+
duplicate: boolean;
|
|
136
|
+
/** When the server accepted the message (the first time, for a duplicate). */
|
|
137
|
+
receivedAt: Date;
|
|
138
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Severity constants. The horn names are aliases of the canonical values:
|
|
3
|
+
* `Severity.Loud === Severity.Warning === 'warning'`.
|
|
4
|
+
*/
|
|
5
|
+
export const Severity = {
|
|
6
|
+
Light: 'info',
|
|
7
|
+
Beep: 'success',
|
|
8
|
+
Loud: 'warning',
|
|
9
|
+
Long: 'error',
|
|
10
|
+
Blast: 'critical',
|
|
11
|
+
Info: 'info',
|
|
12
|
+
Success: 'success',
|
|
13
|
+
Warning: 'warning',
|
|
14
|
+
Error: 'error',
|
|
15
|
+
Critical: 'critical',
|
|
16
|
+
};
|
|
17
|
+
/** Horn alias → canonical severity. */
|
|
18
|
+
export const SEVERITY_ALIASES = {
|
|
19
|
+
light: 'info',
|
|
20
|
+
beep: 'success',
|
|
21
|
+
loud: 'warning',
|
|
22
|
+
long: 'error',
|
|
23
|
+
blast: 'critical',
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Returns the canonical severity for a canonical value or horn alias (case-insensitive), or
|
|
27
|
+
* undefined when it is neither: `normalizeSeverity('LOUD') === 'warning'`.
|
|
28
|
+
*/
|
|
29
|
+
export function normalizeSeverity(value) {
|
|
30
|
+
const v = value.trim().toLowerCase();
|
|
31
|
+
if (SEVERITIES.includes(v))
|
|
32
|
+
return v;
|
|
33
|
+
return SEVERITY_ALIASES[v];
|
|
34
|
+
}
|
|
35
|
+
export const SEVERITIES = ['info', 'success', 'warning', 'error', 'critical'];
|
|
36
|
+
export const PRIORITIES = ['low', 'normal', 'high', 'urgent'];
|
|
37
|
+
export const EVENT_TYPES = ['event', 'problem', 'recovery'];
|
|
38
|
+
export const CATEGORIES = [
|
|
39
|
+
'infrastructure',
|
|
40
|
+
'security',
|
|
41
|
+
'backups',
|
|
42
|
+
'deployments',
|
|
43
|
+
'payments',
|
|
44
|
+
'customers',
|
|
45
|
+
'sales',
|
|
46
|
+
'automation',
|
|
47
|
+
'personal',
|
|
48
|
+
'other',
|
|
49
|
+
];
|
package/dist/esm/uuid.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
let nodeRandomFill;
|
|
2
|
+
async function randomBytes(n) {
|
|
3
|
+
const buf = new Uint8Array(n);
|
|
4
|
+
const webCrypto = globalThis.crypto;
|
|
5
|
+
if (webCrypto?.getRandomValues) {
|
|
6
|
+
webCrypto.getRandomValues(buf);
|
|
7
|
+
return buf;
|
|
8
|
+
}
|
|
9
|
+
// Node 18 has no global `crypto` unless --experimental-global-webcrypto is set.
|
|
10
|
+
if (!nodeRandomFill) {
|
|
11
|
+
const nodeCrypto = await import('node:crypto');
|
|
12
|
+
nodeRandomFill = (b) => nodeCrypto.randomFillSync(b);
|
|
13
|
+
}
|
|
14
|
+
nodeRandomFill(buf);
|
|
15
|
+
return buf;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Returns a new UUIDv7 (RFC 9562): 48-bit Unix milliseconds, then 74 random bits. Time-ordered
|
|
19
|
+
* and unique, so it doubles as an idempotency key you can store before sending.
|
|
20
|
+
*/
|
|
21
|
+
export async function uuidv7(now = Date.now()) {
|
|
22
|
+
const b = await randomBytes(16);
|
|
23
|
+
const ms = Math.max(0, Math.floor(now));
|
|
24
|
+
// 48-bit big-endian timestamp (split to stay within safe integer bit operations).
|
|
25
|
+
const hi = Math.floor(ms / 2 ** 16);
|
|
26
|
+
const lo = ms % 2 ** 16;
|
|
27
|
+
b[0] = (hi >>> 24) & 0xff;
|
|
28
|
+
b[1] = (hi >>> 16) & 0xff;
|
|
29
|
+
b[2] = (hi >>> 8) & 0xff;
|
|
30
|
+
b[3] = hi & 0xff;
|
|
31
|
+
b[4] = (lo >>> 8) & 0xff;
|
|
32
|
+
b[5] = lo & 0xff;
|
|
33
|
+
b[6] = (b[6] & 0x0f) | 0x70; // version 7
|
|
34
|
+
b[8] = (b[8] & 0x3f) | 0x80; // variant 10
|
|
35
|
+
const hex = Array.from(b, (x) => x.toString(16).padStart(2, '0')).join('');
|
|
36
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
37
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type Defaults, type Message } from './types.js';
|
|
2
|
+
/** Limits from contracts/openapi.yaml (and the server's validator). */
|
|
3
|
+
export declare const LIMITS: {
|
|
4
|
+
readonly bodyBytes: number;
|
|
5
|
+
readonly messageBytes: 8192;
|
|
6
|
+
readonly title: 160;
|
|
7
|
+
readonly source: 64;
|
|
8
|
+
readonly environment: 32;
|
|
9
|
+
readonly channel: 64;
|
|
10
|
+
readonly groupKey: 128;
|
|
11
|
+
readonly urlBytes: 2048;
|
|
12
|
+
readonly metadataKeys: 16;
|
|
13
|
+
readonly metadataValue: 512;
|
|
14
|
+
readonly ttlMin: 60;
|
|
15
|
+
readonly ttlMax: 86400;
|
|
16
|
+
readonly idempotencyKey: 128;
|
|
17
|
+
};
|
|
18
|
+
export declare const byteLength: (s: string) => number;
|
|
19
|
+
/** Checks an Idempotency-Key: 1–128 printable ASCII characters (0x21–0x7E). */
|
|
20
|
+
export declare function checkIdempotencyKey(key: unknown): string;
|
|
21
|
+
/**
|
|
22
|
+
* Turns a message into the wire object of `POST /v1/messages`, applying `defaults` and (unless
|
|
23
|
+
* `validate` is false) the cheap checks the server would apply anyway. Throws HonkValidationError
|
|
24
|
+
* listing every invalid field.
|
|
25
|
+
*/
|
|
26
|
+
export declare function buildBody(input: Message, defaults?: Defaults, validate?: boolean): Record<string, unknown>;
|
|
27
|
+
/** Syntactic check matching the server: https, a host, no credentials, no spaces/backslashes, ≤ 2048 bytes. */
|
|
28
|
+
export declare function validUrl(raw: unknown, image: boolean): boolean;
|