aboutsummaryrefslogtreecommitdiff
path: root/src/integrations
diff options
context:
space:
mode:
authorElizabeth Hunt <me@liz.coffee>2025-12-14 20:36:24 -0800
committerElizabeth Hunt <me@liz.coffee>2025-12-14 20:36:24 -0800
commit6bf57766feb8321f860baf300140563cd9539053 (patch)
treed80ff78c2a7f4dbea79f9ee850542aee1b735ef4 /src/integrations
downloadposthook-6bf57766feb8321f860baf300140563cd9539053.tar.gz
posthook-6bf57766feb8321f860baf300140563cd9539053.zip
Init
Diffstat (limited to 'src/integrations')
-rw-r--r--src/integrations/hcaptcha.ts32
-rw-r--r--src/integrations/ntfy.ts40
2 files changed, 72 insertions, 0 deletions
diff --git a/src/integrations/hcaptcha.ts b/src/integrations/hcaptcha.ts
new file mode 100644
index 0000000..78ff356
--- /dev/null
+++ b/src/integrations/hcaptcha.ts
@@ -0,0 +1,32 @@
+import { Either, type IEither } from '@emprespresso/pengueno';
+
+export interface HCaptchaResponse {
+ success: boolean;
+ challenge_ts?: string;
+ hostname?: string;
+ 'error-codes'?: string[];
+}
+
+export async function verifyHCaptcha(token: string, secret: string): Promise<IEither<Error, boolean>> {
+ try {
+ const response = await fetch('https://hcaptcha.com/siteverify', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ },
+ body: new URLSearchParams({
+ secret,
+ response: token,
+ }),
+ });
+
+ if (!response.ok) {
+ return Either.left(new Error(`hCaptcha verification failed: ${response.statusText}`));
+ }
+
+ const result = (await response.json()) as HCaptchaResponse;
+ return Either.right(result.success);
+ } catch (err) {
+ return Either.left(err instanceof Error ? err : new Error(String(err)));
+ }
+}
diff --git a/src/integrations/ntfy.ts b/src/integrations/ntfy.ts
new file mode 100644
index 0000000..cf815ed
--- /dev/null
+++ b/src/integrations/ntfy.ts
@@ -0,0 +1,40 @@
+import { Either, type IEither } from '@emprespresso/pengueno';
+import type { NtfyConfig, StoredRequest } from '../types/index.js';
+
+export interface NtfyNotification {
+ topic: string;
+ title: string;
+ message: string;
+ tags?: string[];
+ priority?: number;
+}
+
+export async function sendNtfyNotification(config: NtfyConfig, request: StoredRequest): Promise<IEither<Error, void>> {
+ if (!config.enabled || !config.server || !config.topic) {
+ return Either.right(<void>undefined);
+ }
+
+ try {
+ const url = `${config.server}/${config.topic}`;
+ const title = `Webhook received: ${request.routeName}`;
+ const message = `Method: ${request.method}\nTimestamp: ${new Date(request.timestamp).toISOString()}\nUUID: ${request.uuid}`;
+
+ const response = await fetch(url, {
+ method: 'POST',
+ headers: {
+ Title: title,
+ Tags: 'webhook,posthook',
+ Priority: '3',
+ },
+ body: message,
+ });
+
+ if (!response.ok) {
+ return Either.left(new Error(`ntfy notification failed: ${response.statusText}`));
+ }
+
+ return Either.right(<void>undefined);
+ } catch (err) {
+ return Either.left(err instanceof Error ? err : new Error(String(err)));
+ }
+}