1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
#!/usr/bin/env node
import {
Either,
getRequiredEnvVars,
LogTraceable,
LogMetricTraceable,
Metric,
TraceUtil,
} from '@emprespresso/pengueno';
import { Infisical, type SecureNote } from '@emprespresso/ci_worker';
import { CoolifyWebhookJob } from '@emprespresso/ci_model';
const eitherJob = getRequiredEnvVars(['webhookUrl']).mapRight(
(baseArgs) =>
<CoolifyWebhookJob>{
type: 'coolify_webhook.js',
arguments: baseArgs,
},
);
const eitherVault = Infisical.getConfigFromEnvironment().mapRight((config) => new Infisical(config));
const webhookMetric = Metric.fromName('coolify_webhook.trigger').asResult();
const _logJob = LogTraceable.of(eitherJob).flatMap(TraceUtil.withTrace('coolify_webhook'));
await LogMetricTraceable.ofLogTraceable(_logJob)
.flatMap(TraceUtil.withMetricTrace(webhookMetric))
.peek((tEitherJob) => tEitherJob.trace.trace('starting coolify webhook trigger! (⑅˘꒳˘)'))
.map((tEitherJob) =>
tEitherJob.get().flatMapAsync((job) =>
eitherVault.flatMapAsync(async (vault) => {
const eitherKey = await vault.unlock(tEitherJob);
tEitherJob.trace.trace('unlocked vault :3');
return eitherKey.mapRight((key) => ({ job, key, vault }));
}),
),
)
.map(async (tEitherJobVault) =>
(await tEitherJobVault.get()).flatMapAsync(({ job, key, vault }) =>
vault
.fetchSecret<SecureNote>(tEitherJobVault, key, 'coolify')
.then((e) => e.mapRight(({ notes }) => ({ job, webhookSecret: notes })))
.finally(() => vault.lock(tEitherJobVault, key)),
),
)
.map(async (tEitherJobAndSecret) => {
const eitherJobAndSecret = await tEitherJobAndSecret.get();
return eitherJobAndSecret.flatMapAsync(async ({ job, webhookSecret }) => {
tEitherJobAndSecret.trace.trace(`triggering webhook at ${job.arguments.webhookUrl} (◕ᴗ◕✿)`);
return Either.fromFailableAsync<Error, string>(() =>
fetch(job.arguments.webhookUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${webhookSecret}`,
},
body: JSON.stringify({}),
}).then(async (response) => {
if (!response.ok) {
throw new Error(
`webhook request failed with status ${response.status}: ${await response.text()}`,
);
}
return response.text();
}),
).then((e) => {
e.mapRight((responseText) =>
tEitherJobAndSecret.trace.trace(`webhook response: ${responseText}`),
);
return e;
});
});
})
.peek(TraceUtil.promiseify(TraceUtil.traceResultingEither(webhookMetric)))
.map(async (tEitherJob) => {
const eitherJob = await tEitherJob.get();
return eitherJob.fold(
(e) => Promise.reject(e),
() => Promise.resolve(0),
);
})
.get();
|