@hookflo/tern 4.2.5-beta → 4.2.9-beta
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/README.md +34 -1
- package/dist/adapters/cloudflare.d.ts +3 -0
- package/dist/adapters/cloudflare.js +25 -1
- package/dist/adapters/express.d.ts +3 -0
- package/dist/adapters/express.js +16 -0
- package/dist/adapters/nextjs.d.ts +3 -0
- package/dist/adapters/nextjs.js +25 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +19 -1
- package/dist/notifications/channels/discord/build-payload.js +4 -2
- package/dist/notifications/channels/slack/build-payload.js +4 -2
- package/dist/notifications/constants.d.ts +4 -4
- package/dist/notifications/constants.js +4 -4
- package/dist/notifications/dispatch.d.ts +8 -0
- package/dist/notifications/dispatch.js +13 -0
- package/dist/notifications/utils.js +27 -16
- package/dist/upstash/controls.js +5 -2
- package/dist/upstash/queue.js +5 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -512,7 +512,40 @@ await controls.alert({
|
|
|
512
512
|
- `controls.alert()` with no params sends a normal (non-DLQ) alert with internal defaults.
|
|
513
513
|
- `controls.alert({ dlq: true, dlqId })` sends a DLQ alert and attempts replay internally via `controls.replay(dlqId)`.
|
|
514
514
|
- `eventId` is auto-filled from `dlqId` for DLQ alerts.
|
|
515
|
-
- Optional overrides like `message`, `metadata`, `source`, or `branding`
|
|
515
|
+
- Optional overrides like `title`, `message`, `metadata`, `source`, or `branding` are used directly in Slack/Discord payloads.
|
|
516
|
+
|
|
517
|
+
### Adapter-level alerts (works with and without queue)
|
|
518
|
+
|
|
519
|
+
If you are not using Upstash controls, you can enable alerting directly in adapters by providing `alerts`.
|
|
520
|
+
This works in **both queue and non-queue** modes.
|
|
521
|
+
|
|
522
|
+
```ts
|
|
523
|
+
import { createWebhookHandler } from '@hookflo/tern/nextjs';
|
|
524
|
+
|
|
525
|
+
export const POST = createWebhookHandler({
|
|
526
|
+
platform: 'stripe',
|
|
527
|
+
secret: process.env.STRIPE_WEBHOOK_SECRET!,
|
|
528
|
+
alerts: {
|
|
529
|
+
slack: { webhookUrl: process.env.SLACK_WEBHOOK_URL! },
|
|
530
|
+
discord: { webhookUrl: process.env.DISCORD_WEBHOOK_URL! },
|
|
531
|
+
},
|
|
532
|
+
alert: {
|
|
533
|
+
title: 'Alert Recieved',
|
|
534
|
+
message: 'Alert received in handler',
|
|
535
|
+
},
|
|
536
|
+
handler: async (payload, metadata) => {
|
|
537
|
+
return { ok: true };
|
|
538
|
+
},
|
|
539
|
+
});
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
- In non-queue mode, alerts include `source` (platform) and canonical `eventId` from verification.
|
|
543
|
+
- In queue mode, normal alerts are sent on successful enqueue (DLQ alerting remains Upstash-controls based).
|
|
544
|
+
- Adapter-level alert calls do **not** auto-inject metadata; pass explicit alert fields via `alert` for predictable payloads.
|
|
545
|
+
|
|
546
|
+
### Core SDK queue + alerts
|
|
547
|
+
|
|
548
|
+
`WebhookVerificationService.handleWithQueue(...)` also supports alerting through the same `alerts` + `alert` options, so core SDK users get the same behavior as framework adapters.
|
|
516
549
|
|
|
517
550
|
## Testing
|
|
518
551
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { WebhookPlatform, NormalizeOptions } from '../types';
|
|
2
2
|
import { QueueOption } from '../upstash/types';
|
|
3
|
+
import type { AlertConfig, SendAlertOptions } from '../notifications/types';
|
|
3
4
|
export interface CloudflareWebhookHandlerOptions<TEnv = Record<string, unknown>, TPayload = any, TMetadata extends Record<string, unknown> = Record<string, unknown>, TResponse = unknown> {
|
|
4
5
|
platform: WebhookPlatform;
|
|
5
6
|
secret?: string;
|
|
@@ -7,6 +8,8 @@ export interface CloudflareWebhookHandlerOptions<TEnv = Record<string, unknown>,
|
|
|
7
8
|
toleranceInSeconds?: number;
|
|
8
9
|
normalize?: boolean | NormalizeOptions;
|
|
9
10
|
queue?: QueueOption;
|
|
11
|
+
alerts?: AlertConfig;
|
|
12
|
+
alert?: Omit<SendAlertOptions, 'dlq' | 'dlqId' | 'source' | 'eventId'>;
|
|
10
13
|
onError?: (error: Error) => void;
|
|
11
14
|
handler: (payload: TPayload, env: TEnv, metadata: TMetadata) => Promise<TResponse> | TResponse;
|
|
12
15
|
}
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.createWebhookHandler = createWebhookHandler;
|
|
4
4
|
const index_1 = require("../index");
|
|
5
5
|
const queue_1 = require("../upstash/queue");
|
|
6
|
+
const dispatch_1 = require("../notifications/dispatch");
|
|
6
7
|
function createWebhookHandler(options) {
|
|
7
8
|
return async (request, env) => {
|
|
8
9
|
try {
|
|
@@ -13,18 +14,41 @@ function createWebhookHandler(options) {
|
|
|
13
14
|
}
|
|
14
15
|
if (options.queue) {
|
|
15
16
|
const queueConfig = (0, queue_1.resolveQueueConfig)(options.queue);
|
|
16
|
-
|
|
17
|
+
const response = await (0, queue_1.handleQueuedRequest)(request, {
|
|
17
18
|
platform: options.platform,
|
|
18
19
|
secret,
|
|
19
20
|
queueConfig,
|
|
20
21
|
handler: (payload, metadata) => options.handler(payload, env, metadata),
|
|
21
22
|
toleranceInSeconds: options.toleranceInSeconds ?? 300,
|
|
22
23
|
});
|
|
24
|
+
if (response.ok) {
|
|
25
|
+
let eventId;
|
|
26
|
+
try {
|
|
27
|
+
const body = await response.clone().json();
|
|
28
|
+
eventId = typeof body.eventId === 'string' ? body.eventId : undefined;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
eventId = undefined;
|
|
32
|
+
}
|
|
33
|
+
await (0, dispatch_1.dispatchWebhookAlert)({
|
|
34
|
+
alerts: options.alerts,
|
|
35
|
+
source: options.platform,
|
|
36
|
+
eventId,
|
|
37
|
+
alert: options.alert,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return response;
|
|
23
41
|
}
|
|
24
42
|
const result = await index_1.WebhookVerificationService.verifyWithPlatformConfig(request, options.platform, secret, options.toleranceInSeconds, options.normalize);
|
|
25
43
|
if (!result.isValid) {
|
|
26
44
|
return Response.json({ error: result.error, errorCode: result.errorCode, platform: result.platform, metadata: result.metadata }, { status: 400 });
|
|
27
45
|
}
|
|
46
|
+
await (0, dispatch_1.dispatchWebhookAlert)({
|
|
47
|
+
alerts: options.alerts,
|
|
48
|
+
source: options.platform,
|
|
49
|
+
eventId: result.eventId,
|
|
50
|
+
alert: options.alert,
|
|
51
|
+
});
|
|
28
52
|
const data = await options.handler(result.payload, env, (result.metadata || {}));
|
|
29
53
|
return Response.json(data);
|
|
30
54
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { WebhookPlatform, WebhookVerificationResult, NormalizeOptions } from '../types';
|
|
2
2
|
import { QueueOption } from '../upstash/types';
|
|
3
3
|
import { MinimalNodeRequest } from './shared';
|
|
4
|
+
import type { AlertConfig, SendAlertOptions } from '../notifications/types';
|
|
4
5
|
export interface ExpressLikeResponse {
|
|
5
6
|
status: (code: number) => ExpressLikeResponse;
|
|
6
7
|
json: (payload: unknown) => unknown;
|
|
@@ -15,6 +16,8 @@ export interface ExpressWebhookMiddlewareOptions {
|
|
|
15
16
|
toleranceInSeconds?: number;
|
|
16
17
|
normalize?: boolean | NormalizeOptions;
|
|
17
18
|
queue?: QueueOption;
|
|
19
|
+
alerts?: AlertConfig;
|
|
20
|
+
alert?: Omit<SendAlertOptions, 'dlq' | 'dlqId' | 'source' | 'eventId'>;
|
|
18
21
|
onError?: (error: Error) => void;
|
|
19
22
|
strictRawBody?: boolean;
|
|
20
23
|
}
|
package/dist/adapters/express.js
CHANGED
|
@@ -4,6 +4,7 @@ exports.createWebhookMiddleware = createWebhookMiddleware;
|
|
|
4
4
|
const index_1 = require("../index");
|
|
5
5
|
const queue_1 = require("../upstash/queue");
|
|
6
6
|
const shared_1 = require("./shared");
|
|
7
|
+
const dispatch_1 = require("../notifications/dispatch");
|
|
7
8
|
function createWebhookMiddleware(options) {
|
|
8
9
|
return async (req, res, next) => {
|
|
9
10
|
try {
|
|
@@ -36,6 +37,15 @@ function createWebhookMiddleware(options) {
|
|
|
36
37
|
}
|
|
37
38
|
}
|
|
38
39
|
res.status(queueResponse.status).json(body ?? {});
|
|
40
|
+
if (queueResponse.ok) {
|
|
41
|
+
const queueResult = body && typeof body === 'object' ? body : undefined;
|
|
42
|
+
await (0, dispatch_1.dispatchWebhookAlert)({
|
|
43
|
+
alerts: options.alerts,
|
|
44
|
+
source: options.platform,
|
|
45
|
+
eventId: typeof queueResult?.eventId === 'string' ? queueResult.eventId : undefined,
|
|
46
|
+
alert: options.alert,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
39
49
|
return;
|
|
40
50
|
}
|
|
41
51
|
const result = await index_1.WebhookVerificationService.verifyWithPlatformConfig(webRequest, options.platform, options.secret, options.toleranceInSeconds, options.normalize);
|
|
@@ -49,6 +59,12 @@ function createWebhookMiddleware(options) {
|
|
|
49
59
|
return;
|
|
50
60
|
}
|
|
51
61
|
req.webhook = result;
|
|
62
|
+
await (0, dispatch_1.dispatchWebhookAlert)({
|
|
63
|
+
alerts: options.alerts,
|
|
64
|
+
source: options.platform,
|
|
65
|
+
eventId: result.eventId,
|
|
66
|
+
alert: options.alert,
|
|
67
|
+
});
|
|
52
68
|
next();
|
|
53
69
|
}
|
|
54
70
|
catch (error) {
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { WebhookPlatform, NormalizeOptions } from '../types';
|
|
2
2
|
import { QueueOption } from '../upstash/types';
|
|
3
|
+
import type { AlertConfig, SendAlertOptions } from '../notifications/types';
|
|
3
4
|
export interface NextWebhookHandlerOptions<TPayload = any, TMetadata extends Record<string, unknown> = Record<string, unknown>, TResponse = unknown> {
|
|
4
5
|
platform: WebhookPlatform;
|
|
5
6
|
secret: string;
|
|
6
7
|
toleranceInSeconds?: number;
|
|
7
8
|
normalize?: boolean | NormalizeOptions;
|
|
8
9
|
queue?: QueueOption;
|
|
10
|
+
alerts?: AlertConfig;
|
|
11
|
+
alert?: Omit<SendAlertOptions, 'dlq' | 'dlqId' | 'source' | 'eventId'>;
|
|
9
12
|
onError?: (error: Error) => void;
|
|
10
13
|
handler: (payload: TPayload, metadata: TMetadata) => Promise<TResponse> | TResponse;
|
|
11
14
|
}
|
package/dist/adapters/nextjs.js
CHANGED
|
@@ -3,23 +3,47 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.createWebhookHandler = createWebhookHandler;
|
|
4
4
|
const index_1 = require("../index");
|
|
5
5
|
const queue_1 = require("../upstash/queue");
|
|
6
|
+
const dispatch_1 = require("../notifications/dispatch");
|
|
6
7
|
function createWebhookHandler(options) {
|
|
7
8
|
return async (request) => {
|
|
8
9
|
try {
|
|
9
10
|
if (options.queue) {
|
|
10
11
|
const queueConfig = (0, queue_1.resolveQueueConfig)(options.queue);
|
|
11
|
-
|
|
12
|
+
const response = await (0, queue_1.handleQueuedRequest)(request, {
|
|
12
13
|
platform: options.platform,
|
|
13
14
|
secret: options.secret,
|
|
14
15
|
queueConfig,
|
|
15
16
|
handler: options.handler,
|
|
16
17
|
toleranceInSeconds: options.toleranceInSeconds ?? 300,
|
|
17
18
|
});
|
|
19
|
+
if (response.ok) {
|
|
20
|
+
let eventId;
|
|
21
|
+
try {
|
|
22
|
+
const body = await response.clone().json();
|
|
23
|
+
eventId = typeof body.eventId === 'string' ? body.eventId : undefined;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
eventId = undefined;
|
|
27
|
+
}
|
|
28
|
+
await (0, dispatch_1.dispatchWebhookAlert)({
|
|
29
|
+
alerts: options.alerts,
|
|
30
|
+
source: options.platform,
|
|
31
|
+
eventId,
|
|
32
|
+
alert: options.alert,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return response;
|
|
18
36
|
}
|
|
19
37
|
const result = await index_1.WebhookVerificationService.verifyWithPlatformConfig(request, options.platform, options.secret, options.toleranceInSeconds, options.normalize);
|
|
20
38
|
if (!result.isValid) {
|
|
21
39
|
return Response.json({ error: result.error, errorCode: result.errorCode, platform: result.platform, metadata: result.metadata }, { status: 400 });
|
|
22
40
|
}
|
|
41
|
+
await (0, dispatch_1.dispatchWebhookAlert)({
|
|
42
|
+
alerts: options.alerts,
|
|
43
|
+
source: options.platform,
|
|
44
|
+
eventId: result.eventId,
|
|
45
|
+
alert: options.alert,
|
|
46
|
+
});
|
|
23
47
|
const data = await options.handler(result.payload, (result.metadata || {}));
|
|
24
48
|
return Response.json(data);
|
|
25
49
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { WebhookConfig, WebhookVerificationResult, WebhookPlatform, SignatureConfig, MultiPlatformSecrets, NormalizeOptions } from './types';
|
|
2
2
|
import type { QueueOption } from './upstash/types';
|
|
3
|
+
import type { AlertConfig, SendAlertOptions } from './notifications/types';
|
|
3
4
|
export declare class WebhookVerificationService {
|
|
4
5
|
static verify<TPayload = unknown>(request: Request, config: WebhookConfig): Promise<WebhookVerificationResult<TPayload>>;
|
|
5
6
|
private static getVerifier;
|
|
@@ -20,6 +21,8 @@ export declare class WebhookVerificationService {
|
|
|
20
21
|
platform: WebhookPlatform;
|
|
21
22
|
secret: string;
|
|
22
23
|
queue: QueueOption;
|
|
24
|
+
alerts?: AlertConfig;
|
|
25
|
+
alert?: Omit<SendAlertOptions, 'dlq' | 'dlqId' | 'source' | 'eventId'>;
|
|
23
26
|
handler: (payload: unknown, metadata: Record<string, unknown>) => Promise<unknown> | unknown;
|
|
24
27
|
toleranceInSeconds?: number;
|
|
25
28
|
}): Promise<Response>;
|
package/dist/index.js
CHANGED
|
@@ -42,6 +42,7 @@ const algorithms_1 = require("./verifiers/algorithms");
|
|
|
42
42
|
const custom_algorithms_1 = require("./verifiers/custom-algorithms");
|
|
43
43
|
const algorithms_2 = require("./platforms/algorithms");
|
|
44
44
|
const simple_1 = require("./normalization/simple");
|
|
45
|
+
const dispatch_1 = require("./notifications/dispatch");
|
|
45
46
|
class WebhookVerificationService {
|
|
46
47
|
static async verify(request, config) {
|
|
47
48
|
const verifier = this.getVerifier(config);
|
|
@@ -324,13 +325,30 @@ class WebhookVerificationService {
|
|
|
324
325
|
static async handleWithQueue(request, options) {
|
|
325
326
|
const { resolveQueueConfig, handleQueuedRequest } = await Promise.resolve().then(() => __importStar(require('./upstash/queue')));
|
|
326
327
|
const queueConfig = resolveQueueConfig(options.queue);
|
|
327
|
-
|
|
328
|
+
const response = await handleQueuedRequest(request, {
|
|
328
329
|
platform: options.platform,
|
|
329
330
|
secret: options.secret,
|
|
330
331
|
queueConfig,
|
|
331
332
|
handler: options.handler,
|
|
332
333
|
toleranceInSeconds: options.toleranceInSeconds ?? 300,
|
|
333
334
|
});
|
|
335
|
+
if (response.ok) {
|
|
336
|
+
let eventId;
|
|
337
|
+
try {
|
|
338
|
+
const body = await response.clone().json();
|
|
339
|
+
eventId = typeof body.eventId === 'string' ? body.eventId : undefined;
|
|
340
|
+
}
|
|
341
|
+
catch {
|
|
342
|
+
eventId = undefined;
|
|
343
|
+
}
|
|
344
|
+
await (0, dispatch_1.dispatchWebhookAlert)({
|
|
345
|
+
alerts: options.alerts,
|
|
346
|
+
source: options.platform,
|
|
347
|
+
eventId,
|
|
348
|
+
alert: options.alert,
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
return response;
|
|
334
352
|
}
|
|
335
353
|
static async verifyTokenBased(request, webhookId, webhookToken) {
|
|
336
354
|
return this.verifyTokenAuth(request, webhookId, webhookToken);
|
|
@@ -5,10 +5,12 @@ const utils_1 = require("../../utils");
|
|
|
5
5
|
const constants_1 = require("../../constants");
|
|
6
6
|
function buildDiscordPayload(input) {
|
|
7
7
|
const isDLQ = input.dlq;
|
|
8
|
-
const
|
|
9
|
-
const
|
|
8
|
+
const fallbackTitle = isDLQ ? "Dead Letter Queue — Event Failed" : "Webhook Received";
|
|
9
|
+
const title = input.title?.trim() ? input.title : fallbackTitle;
|
|
10
|
+
const fallbackDescription = isDLQ
|
|
10
11
|
? "Event exhausted all retries. Manual replay required."
|
|
11
12
|
: "Event verified and queued for processing.";
|
|
13
|
+
const description = input.message?.trim() ? input.message : fallbackDescription;
|
|
12
14
|
const fields = [];
|
|
13
15
|
if (input.source) {
|
|
14
16
|
fields.push({ name: "Platform", value: input.source, inline: true });
|
|
@@ -5,10 +5,12 @@ const utils_1 = require("../../utils");
|
|
|
5
5
|
const constants_1 = require("../../constants");
|
|
6
6
|
function buildSlackPayload(input) {
|
|
7
7
|
const isDLQ = input.dlq;
|
|
8
|
-
const
|
|
9
|
-
const
|
|
8
|
+
const fallbackTitle = isDLQ ? "Dead Letter Queue — Event Failed" : "Webhook Received";
|
|
9
|
+
const title = input.title?.trim() ? input.title : fallbackTitle;
|
|
10
|
+
const fallbackMessage = isDLQ
|
|
10
11
|
? "Event exhausted all retries. Manual replay required."
|
|
11
12
|
: "Event verified and queued for processing.";
|
|
13
|
+
const message = input.message?.trim() ? input.message : fallbackMessage;
|
|
12
14
|
const fields = [
|
|
13
15
|
input.source
|
|
14
16
|
? { type: "mrkdwn", text: `*Platform*\n${input.source}` }
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { AlertSeverity } from './types';
|
|
2
2
|
export declare const TERN_BRAND_URL = "https://tern.hookflo.com";
|
|
3
|
-
export declare const DEFAULT_DLQ_TITLE = "
|
|
4
|
-
export declare const DEFAULT_ALERT_TITLE = "Webhook
|
|
3
|
+
export declare const DEFAULT_DLQ_TITLE = "Dead Letter Queue \u2014 Event Failed";
|
|
4
|
+
export declare const DEFAULT_ALERT_TITLE = "Webhook Received";
|
|
5
5
|
export declare const DEFAULT_REPLAY_LABEL = "Replay DLQ Event";
|
|
6
|
-
export declare const DEFAULT_DLQ_MESSAGE = "
|
|
7
|
-
export declare const DEFAULT_ALERT_MESSAGE = "
|
|
6
|
+
export declare const DEFAULT_DLQ_MESSAGE = "Event exhausted all retries. Manual replay required.";
|
|
7
|
+
export declare const DEFAULT_ALERT_MESSAGE = "Event verified and queued for processing.";
|
|
8
8
|
export declare const severityColorMap: Record<AlertSeverity, string>;
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.severityColorMap = exports.DEFAULT_ALERT_MESSAGE = exports.DEFAULT_DLQ_MESSAGE = exports.DEFAULT_REPLAY_LABEL = exports.DEFAULT_ALERT_TITLE = exports.DEFAULT_DLQ_TITLE = exports.TERN_BRAND_URL = void 0;
|
|
4
4
|
exports.TERN_BRAND_URL = 'https://tern.hookflo.com';
|
|
5
|
-
exports.DEFAULT_DLQ_TITLE = '
|
|
6
|
-
exports.DEFAULT_ALERT_TITLE = 'Webhook
|
|
5
|
+
exports.DEFAULT_DLQ_TITLE = 'Dead Letter Queue — Event Failed';
|
|
6
|
+
exports.DEFAULT_ALERT_TITLE = 'Webhook Received';
|
|
7
7
|
exports.DEFAULT_REPLAY_LABEL = 'Replay DLQ Event';
|
|
8
|
-
exports.DEFAULT_DLQ_MESSAGE = '
|
|
9
|
-
exports.DEFAULT_ALERT_MESSAGE = '
|
|
8
|
+
exports.DEFAULT_DLQ_MESSAGE = 'Event exhausted all retries. Manual replay required.';
|
|
9
|
+
exports.DEFAULT_ALERT_MESSAGE = 'Event verified and queued for processing.';
|
|
10
10
|
exports.severityColorMap = {
|
|
11
11
|
info: '#3B82F6',
|
|
12
12
|
warning: '#F59E0B',
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AlertConfig, SendAlertOptions } from './types';
|
|
2
|
+
export interface DispatchWebhookAlertInput {
|
|
3
|
+
alerts?: AlertConfig;
|
|
4
|
+
source?: string;
|
|
5
|
+
eventId?: string;
|
|
6
|
+
alert?: Omit<SendAlertOptions, 'dlq' | 'dlqId' | 'source' | 'eventId'>;
|
|
7
|
+
}
|
|
8
|
+
export declare function dispatchWebhookAlert(input: DispatchWebhookAlertInput): Promise<void>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.dispatchWebhookAlert = dispatchWebhookAlert;
|
|
4
|
+
const send_alert_1 = require("./send-alert");
|
|
5
|
+
async function dispatchWebhookAlert(input) {
|
|
6
|
+
if (!input.alerts)
|
|
7
|
+
return;
|
|
8
|
+
await (0, send_alert_1.sendAlert)(input.alerts, {
|
|
9
|
+
...(input.alert || {}),
|
|
10
|
+
source: input.source,
|
|
11
|
+
eventId: input.eventId,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
@@ -16,29 +16,40 @@ function asNonEmptyString(value) {
|
|
|
16
16
|
function asObject(value) {
|
|
17
17
|
return value && typeof value === 'object' ? value : undefined;
|
|
18
18
|
}
|
|
19
|
+
function pickNonEmptyString(...values) {
|
|
20
|
+
for (const value of values) {
|
|
21
|
+
const normalized = asNonEmptyString(value);
|
|
22
|
+
if (normalized)
|
|
23
|
+
return normalized;
|
|
24
|
+
}
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
function resolveSourceFromObject(value) {
|
|
28
|
+
const object = asObject(value);
|
|
29
|
+
if (!object)
|
|
30
|
+
return undefined;
|
|
31
|
+
return pickNonEmptyString(object.platform, object.provider, object.source, object.service, object.origin, object.type);
|
|
32
|
+
}
|
|
33
|
+
function resolveEventIdFromObject(value) {
|
|
34
|
+
const object = asObject(value);
|
|
35
|
+
if (!object)
|
|
36
|
+
return undefined;
|
|
37
|
+
return pickNonEmptyString(object.eventId, object.event_id, object.id, object.request_id, object.webhook_id, object.messageId, object.message_id);
|
|
38
|
+
}
|
|
19
39
|
function resolveSource(options) {
|
|
20
40
|
const metadata = options.metadata || {};
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
41
|
+
const metadataPayload = asObject(metadata.payload);
|
|
42
|
+
const metadataEvent = asObject(metadata.event);
|
|
43
|
+
const metadataData = asObject(metadata.data);
|
|
44
|
+
const metadataBody = asObject(metadata.body);
|
|
45
|
+
return pickNonEmptyString(options.source, metadata.source, metadata.platform, metadata.provider, metadata.eventSource, resolveSourceFromObject(metadataPayload), resolveSourceFromObject(metadataEvent), resolveSourceFromObject(metadataData), resolveSourceFromObject(metadataBody));
|
|
25
46
|
}
|
|
26
47
|
function resolveEventId(options) {
|
|
27
48
|
const metadata = options.metadata || {};
|
|
28
49
|
const metadataPayload = asObject(metadata.payload);
|
|
29
50
|
const metadataEvent = asObject(metadata.event);
|
|
30
51
|
const metadataData = asObject(metadata.data);
|
|
31
|
-
return
|
|
32
|
-
|| asNonEmptyString(options.dlqId)
|
|
33
|
-
|| asNonEmptyString(metadata.eventId)
|
|
34
|
-
|| asNonEmptyString(metadata.messageId)
|
|
35
|
-
|| asNonEmptyString(metadata.webhookId)
|
|
36
|
-
|| asNonEmptyString(metadata.id)
|
|
37
|
-
|| asNonEmptyString(metadataPayload?.id)
|
|
38
|
-
|| asNonEmptyString(metadataPayload?.eventId)
|
|
39
|
-
|| asNonEmptyString(metadataPayload?.request_id)
|
|
40
|
-
|| asNonEmptyString(metadataEvent?.id)
|
|
41
|
-
|| asNonEmptyString(metadataData?.id);
|
|
52
|
+
return pickNonEmptyString(options.eventId, options.dlqId, metadata.eventId, metadata.event_id, metadata.messageId, metadata.message_id, metadata.webhookId, metadata.webhook_id, metadata.id, resolveEventIdFromObject(metadataPayload), resolveEventIdFromObject(metadataEvent), resolveEventIdFromObject(metadataData));
|
|
42
53
|
}
|
|
43
54
|
function resolveDestinations(config) {
|
|
44
55
|
const destinations = [];
|
|
@@ -59,7 +70,7 @@ function normalizeAlertOptions(options) {
|
|
|
59
70
|
return {
|
|
60
71
|
...options,
|
|
61
72
|
dlq: isDlq,
|
|
62
|
-
source: resolveSource(options),
|
|
73
|
+
source: resolveSource(options) || 'unknown',
|
|
63
74
|
title,
|
|
64
75
|
message,
|
|
65
76
|
severity,
|
package/dist/upstash/controls.js
CHANGED
|
@@ -52,6 +52,9 @@ function deriveStatus(value) {
|
|
|
52
52
|
return 'failed';
|
|
53
53
|
return 'retrying';
|
|
54
54
|
}
|
|
55
|
+
function withoutUndefined(value) {
|
|
56
|
+
return Object.fromEntries(Object.entries(value).filter(([, entryValue]) => entryValue !== undefined));
|
|
57
|
+
}
|
|
55
58
|
function createTernControls(config) {
|
|
56
59
|
return {
|
|
57
60
|
async dlq() {
|
|
@@ -166,12 +169,12 @@ function createTernControls(config) {
|
|
|
166
169
|
...options,
|
|
167
170
|
source: resolvedSource,
|
|
168
171
|
eventId: resolvedEventId || options.dlqId,
|
|
169
|
-
metadata: {
|
|
172
|
+
metadata: withoutUndefined({
|
|
170
173
|
...(options.metadata || {}),
|
|
171
174
|
source: resolvedSource || options.metadata?.source,
|
|
172
175
|
eventId: resolvedEventId || options.metadata?.eventId,
|
|
173
176
|
...replayMeta,
|
|
174
|
-
},
|
|
177
|
+
}),
|
|
175
178
|
});
|
|
176
179
|
},
|
|
177
180
|
};
|
package/dist/upstash/queue.js
CHANGED
|
@@ -194,7 +194,11 @@ async function handleReceive(request, platform, secret, queueConfig, toleranceIn
|
|
|
194
194
|
}
|
|
195
195
|
try {
|
|
196
196
|
await client.publishJSON(publishPayload);
|
|
197
|
-
return new Response(JSON.stringify({
|
|
197
|
+
return new Response(JSON.stringify({
|
|
198
|
+
queued: true,
|
|
199
|
+
platform,
|
|
200
|
+
eventId: verificationResult.eventId,
|
|
201
|
+
}), {
|
|
198
202
|
status: 200,
|
|
199
203
|
headers: { 'Content-Type': 'application/json' },
|
|
200
204
|
});
|
package/package.json
CHANGED