@teever/ez-hook-effect 0.4.4 → 0.5.1
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 +88 -10
- package/dist/errors/WebhookError.d.ts +142 -3
- package/dist/errors/WebhookError.js +322 -0
- package/dist/errors/WebhookError.js.map +1 -0
- package/dist/errors/index.js +2 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +7 -3
- package/dist/index.js +493 -264
- package/dist/index.js.map +16 -14
- package/dist/layers/Config.d.ts +3 -3
- package/dist/layers/Config.js +166 -0
- package/dist/layers/Config.js.map +1 -0
- package/dist/layers/Default.d.ts +6 -0
- package/dist/layers/Default.js +9 -0
- package/dist/layers/Default.js.map +1 -0
- package/dist/layers/HttpClient.d.ts +8 -4
- package/dist/layers/HttpClient.js +209 -0
- package/dist/layers/HttpClient.js.map +1 -0
- package/dist/layers/index.js +3 -0
- package/dist/layers/index.js.map +1 -0
- package/dist/pipes/Embed.d.ts +2 -2
- package/dist/pipes/Embed.js +198 -0
- package/dist/pipes/Embed.js.map +1 -0
- package/dist/pipes/Webhook.d.ts +3 -2
- package/dist/pipes/Webhook.js +46 -0
- package/dist/pipes/Webhook.js.map +1 -0
- package/dist/pipes/index.js +3 -0
- package/dist/pipes/index.js.map +1 -0
- package/dist/schemas/Common.d.ts +6 -6
- package/dist/schemas/Common.js +30 -0
- package/dist/schemas/Common.js.map +1 -0
- package/dist/schemas/Discord.d.ts +1 -1
- package/dist/schemas/Discord.js +19 -0
- package/dist/schemas/Discord.js.map +1 -0
- package/dist/schemas/Embed.d.ts +58 -229
- package/dist/schemas/Embed.js +139 -0
- package/dist/schemas/Embed.js.map +1 -0
- package/dist/schemas/Field.d.ts +6 -27
- package/dist/schemas/Field.js +25 -0
- package/dist/schemas/Field.js.map +1 -0
- package/dist/schemas/Webhook.d.ts +42 -160
- package/dist/schemas/Webhook.js +87 -0
- package/dist/schemas/Webhook.js.map +1 -0
- package/dist/schemas/index.js +6 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/services/WebhookService.d.ts +27 -5
- package/dist/services/WebhookService.js +116 -0
- package/dist/services/WebhookService.js.map +1 -0
- package/dist/services/index.js +2 -0
- package/dist/services/index.js.map +1 -0
- package/dist/utils/normalize.d.ts +1 -0
- package/dist/utils/normalize.js +17 -0
- package/dist/utils/normalize.js.map +1 -0
- package/package.json +56 -54
package/dist/index.js
CHANGED
|
@@ -55,28 +55,30 @@ var pathToString = (path) => {
|
|
|
55
55
|
}, "$");
|
|
56
56
|
};
|
|
57
57
|
var toArray = (value) => Array.isArray(value) ? value : [value];
|
|
58
|
+
var getIssueProp = (issue, key) => issue[key];
|
|
58
59
|
var extractIssuesFromParseIssue = (issue, currentPath = []) => {
|
|
59
60
|
const issues = [];
|
|
60
61
|
switch (issue._tag) {
|
|
61
|
-
case "
|
|
62
|
-
const
|
|
62
|
+
case "InvalidType": {
|
|
63
|
+
const ast = getIssueProp(issue, "ast");
|
|
64
|
+
const message = getIssueProp(issue, "message") ?? `Expected ${ast?._tag}`;
|
|
63
65
|
issues.push({
|
|
64
66
|
path: pathToString(currentPath),
|
|
65
67
|
message,
|
|
66
68
|
constraint: extractConstraint(message) ?? "Type",
|
|
67
|
-
actual: truncateValue(issue
|
|
69
|
+
actual: truncateValue(getIssueProp(issue, "actual"))
|
|
68
70
|
});
|
|
69
71
|
break;
|
|
70
72
|
}
|
|
71
73
|
case "Forbidden": {
|
|
72
74
|
issues.push({
|
|
73
75
|
path: pathToString(currentPath),
|
|
74
|
-
message: issue
|
|
76
|
+
message: getIssueProp(issue, "message") ?? "Value is forbidden",
|
|
75
77
|
constraint: "Forbidden"
|
|
76
78
|
});
|
|
77
79
|
break;
|
|
78
80
|
}
|
|
79
|
-
case "
|
|
81
|
+
case "MissingKey": {
|
|
80
82
|
issues.push({
|
|
81
83
|
path: pathToString(currentPath),
|
|
82
84
|
message: "Required field is missing",
|
|
@@ -84,34 +86,60 @@ var extractIssuesFromParseIssue = (issue, currentPath = []) => {
|
|
|
84
86
|
});
|
|
85
87
|
break;
|
|
86
88
|
}
|
|
87
|
-
case "
|
|
89
|
+
case "UnexpectedKey": {
|
|
88
90
|
issues.push({
|
|
89
91
|
path: pathToString(currentPath),
|
|
90
|
-
message: issue
|
|
92
|
+
message: getIssueProp(issue, "message") ?? "Unexpected field",
|
|
91
93
|
constraint: "Unexpected",
|
|
92
|
-
actual: truncateValue(issue
|
|
94
|
+
actual: truncateValue(getIssueProp(issue, "actual"))
|
|
93
95
|
});
|
|
94
96
|
break;
|
|
95
97
|
}
|
|
96
98
|
case "Pointer": {
|
|
97
|
-
const pathSegments =
|
|
99
|
+
const pathSegments = getIssueProp(issue, "path") ?? [];
|
|
98
100
|
const newPath = [...currentPath, ...pathSegments];
|
|
99
|
-
|
|
101
|
+
const nested = getIssueProp(issue, "issue");
|
|
102
|
+
if (nested)
|
|
103
|
+
issues.push(...extractIssuesFromParseIssue(nested, newPath));
|
|
100
104
|
break;
|
|
101
105
|
}
|
|
102
106
|
case "Composite": {
|
|
103
|
-
const
|
|
107
|
+
const rawIssues = getIssueProp(issue, "issues");
|
|
108
|
+
const subIssues = rawIssues ? toArray(rawIssues) : [];
|
|
104
109
|
for (const subIssue of subIssues) {
|
|
105
110
|
issues.push(...extractIssuesFromParseIssue(subIssue, currentPath));
|
|
106
111
|
}
|
|
107
112
|
break;
|
|
108
113
|
}
|
|
109
|
-
case "
|
|
110
|
-
|
|
114
|
+
case "Filter":
|
|
115
|
+
case "Encoding": {
|
|
116
|
+
const nested = getIssueProp(issue, "issue");
|
|
117
|
+
if (nested)
|
|
118
|
+
issues.push(...extractIssuesFromParseIssue(nested, currentPath));
|
|
111
119
|
break;
|
|
112
120
|
}
|
|
113
|
-
case "
|
|
114
|
-
|
|
121
|
+
case "InvalidValue":
|
|
122
|
+
case "OneOf":
|
|
123
|
+
case "AnyOf": {
|
|
124
|
+
issues.push({
|
|
125
|
+
path: pathToString(currentPath),
|
|
126
|
+
message: getIssueProp(issue, "message") ?? "Invalid value",
|
|
127
|
+
constraint: "Value",
|
|
128
|
+
actual: truncateValue(getIssueProp(issue, "actual"))
|
|
129
|
+
});
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
default: {
|
|
133
|
+
const message = getIssueProp(issue, "message") ?? "Invalid value";
|
|
134
|
+
const constraint = extractConstraint(message);
|
|
135
|
+
issues.push({
|
|
136
|
+
path: pathToString(currentPath),
|
|
137
|
+
message,
|
|
138
|
+
...constraint !== undefined && { constraint },
|
|
139
|
+
...getIssueProp(issue, "actual") !== undefined && {
|
|
140
|
+
actual: truncateValue(getIssueProp(issue, "actual"))
|
|
141
|
+
}
|
|
142
|
+
});
|
|
115
143
|
break;
|
|
116
144
|
}
|
|
117
145
|
}
|
|
@@ -187,18 +215,87 @@ class FileError extends Data.TaggedError("FileError") {
|
|
|
187
215
|
|
|
188
216
|
class HttpError extends Data.TaggedError("HttpError") {
|
|
189
217
|
}
|
|
218
|
+
var formatWebhookError = (error, options) => {
|
|
219
|
+
switch (error._tag) {
|
|
220
|
+
case "ValidationError":
|
|
221
|
+
return error.format(options);
|
|
222
|
+
case "RateLimitError":
|
|
223
|
+
return `${error.message} (retryAfter=${error.retryAfter}ms)`;
|
|
224
|
+
case "HttpError": {
|
|
225
|
+
const status = error.response?.status;
|
|
226
|
+
return status ? `${error.message} (status=${status})` : error.message;
|
|
227
|
+
}
|
|
228
|
+
default:
|
|
229
|
+
return error.message;
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
var webhookErrorToLogObject = (error) => {
|
|
233
|
+
switch (error._tag) {
|
|
234
|
+
case "ValidationError":
|
|
235
|
+
return {
|
|
236
|
+
tag: error._tag,
|
|
237
|
+
message: error.message,
|
|
238
|
+
issues: error.issues,
|
|
239
|
+
field: error.field,
|
|
240
|
+
value: error.value
|
|
241
|
+
};
|
|
242
|
+
case "RateLimitError":
|
|
243
|
+
return {
|
|
244
|
+
tag: error._tag,
|
|
245
|
+
message: error.message,
|
|
246
|
+
retryAfter: error.retryAfter,
|
|
247
|
+
limit: error.limit,
|
|
248
|
+
remaining: error.remaining,
|
|
249
|
+
reset: error.reset
|
|
250
|
+
};
|
|
251
|
+
case "HttpError":
|
|
252
|
+
return {
|
|
253
|
+
tag: error._tag,
|
|
254
|
+
message: error.message,
|
|
255
|
+
request: error.request,
|
|
256
|
+
response: error.response
|
|
257
|
+
};
|
|
258
|
+
case "NetworkError":
|
|
259
|
+
return {
|
|
260
|
+
tag: error._tag,
|
|
261
|
+
message: error.message,
|
|
262
|
+
statusCode: error.statusCode,
|
|
263
|
+
response: error.response
|
|
264
|
+
};
|
|
265
|
+
case "ConfigError":
|
|
266
|
+
return {
|
|
267
|
+
tag: error._tag,
|
|
268
|
+
message: error.message,
|
|
269
|
+
parameter: error.parameter
|
|
270
|
+
};
|
|
271
|
+
case "FileError":
|
|
272
|
+
return {
|
|
273
|
+
tag: error._tag,
|
|
274
|
+
message: error.message,
|
|
275
|
+
filename: error.filename,
|
|
276
|
+
size: error.size,
|
|
277
|
+
maxSize: error.maxSize
|
|
278
|
+
};
|
|
279
|
+
default:
|
|
280
|
+
return {
|
|
281
|
+
tag: error._tag,
|
|
282
|
+
message: error.message,
|
|
283
|
+
cause: error.cause
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
};
|
|
190
287
|
// src/layers/Config.ts
|
|
191
|
-
import {
|
|
288
|
+
import { Effect, Layer, ServiceMap } from "effect";
|
|
192
289
|
|
|
193
290
|
// src/schemas/Discord.ts
|
|
194
291
|
import { Schema } from "effect";
|
|
195
292
|
var DISCORD_WEBHOOK_REGEX = /^https:\/\/(?:(?:canary|ptb)\.)?discord(?:app)?\.com\/api(?:\/v\d+)?\/webhooks\/(?<id>\d+)\/(?<token>[\w-]+)\/?$/;
|
|
196
|
-
var DiscordWebhookUrl = Schema.String.
|
|
197
|
-
message:
|
|
293
|
+
var DiscordWebhookUrl = Schema.String.check(Schema.isPattern(DISCORD_WEBHOOK_REGEX, {
|
|
294
|
+
message: "Invalid Discord webhook URL"
|
|
198
295
|
}));
|
|
199
296
|
|
|
200
297
|
// src/layers/Config.ts
|
|
201
|
-
class Config extends
|
|
298
|
+
class Config extends ServiceMap.Service()("Config") {
|
|
202
299
|
}
|
|
203
300
|
var validateWebhookUrl = (url) => {
|
|
204
301
|
if (!url || url.trim() === "") {
|
|
@@ -289,16 +386,32 @@ var makeConfig = (webhookUrl, options) => Effect.gen(function* () {
|
|
|
289
386
|
});
|
|
290
387
|
var makeConfigLayer = (webhookUrl, options) => Layer.effect(Config, makeConfig(webhookUrl, options));
|
|
291
388
|
var ConfigFromEnv = Layer.effect(Config, Effect.gen(function* () {
|
|
292
|
-
const
|
|
293
|
-
|
|
389
|
+
const rawWebhookUrl = yield* Effect.sync(() => process.env.DISCORD_WEBHOOK_URL ?? "");
|
|
390
|
+
if (!rawWebhookUrl) {
|
|
391
|
+
return yield* Effect.fail(new ConfigError({
|
|
392
|
+
message: `DISCORD_WEBHOOK_URL environment variable not set.
|
|
294
393
|
` + `Please set DISCORD_WEBHOOK_URL in your environment or .env file.
|
|
295
394
|
` + "See .env.example for all available configuration options.",
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
const
|
|
300
|
-
const
|
|
301
|
-
|
|
395
|
+
parameter: "DISCORD_WEBHOOK_URL"
|
|
396
|
+
}));
|
|
397
|
+
}
|
|
398
|
+
const webhookUrl = yield* validateWebhookUrl(rawWebhookUrl);
|
|
399
|
+
const maxRetries = yield* Effect.sync(() => {
|
|
400
|
+
const v = process.env.WEBHOOK_MAX_RETRIES;
|
|
401
|
+
return v ? Number.parseInt(v, 10) : 3;
|
|
402
|
+
});
|
|
403
|
+
const baseDelayMs = yield* Effect.sync(() => {
|
|
404
|
+
const v = process.env.WEBHOOK_BASE_DELAY_MS;
|
|
405
|
+
return v ? Number.parseInt(v, 10) : 1000;
|
|
406
|
+
});
|
|
407
|
+
const maxDelayMs = yield* Effect.sync(() => {
|
|
408
|
+
const v = process.env.WEBHOOK_MAX_DELAY_MS;
|
|
409
|
+
return v ? Number.parseInt(v, 10) : 60000;
|
|
410
|
+
});
|
|
411
|
+
const enableJitter = yield* Effect.sync(() => {
|
|
412
|
+
const v = process.env.WEBHOOK_ENABLE_JITTER;
|
|
413
|
+
return v ? v === "true" : true;
|
|
414
|
+
});
|
|
302
415
|
yield* validateRetryOptions({ maxRetries, baseDelayMs, maxDelayMs });
|
|
303
416
|
return {
|
|
304
417
|
webhook: {
|
|
@@ -322,8 +435,8 @@ var parseWebhookUrl = (url) => Effect.gen(function* () {
|
|
|
322
435
|
return { id, token };
|
|
323
436
|
});
|
|
324
437
|
// src/layers/HttpClient.ts
|
|
325
|
-
import {
|
|
326
|
-
class HttpClient extends
|
|
438
|
+
import { Duration, Effect as Effect2, Layer as Layer2, Schedule, ServiceMap as ServiceMap2 } from "effect";
|
|
439
|
+
class HttpClient extends ServiceMap2.Service()("HttpClient") {
|
|
327
440
|
}
|
|
328
441
|
var parseRateLimitHeaders = (headers) => {
|
|
329
442
|
const retryAfterHeader = headers["retry-after"];
|
|
@@ -376,13 +489,17 @@ var defaultRetryConfig = {
|
|
|
376
489
|
jitter: true
|
|
377
490
|
};
|
|
378
491
|
var createRetrySchedule = (config) => {
|
|
492
|
+
const capDelay = (delay) => Duration.isLessThanOrEqualTo(delay, config.maxDelay) ? delay : config.maxDelay;
|
|
379
493
|
let policy = Schedule.exponential(config.baseDelay, 2);
|
|
380
|
-
policy = policy.pipe(Schedule.delayed((d) => Duration.lessThanOrEqualTo(d, config.maxDelay) ? d : config.maxDelay));
|
|
381
494
|
if (config.jitter) {
|
|
382
|
-
policy = policy.pipe(Schedule.
|
|
495
|
+
policy = policy.pipe(Schedule.modifyDelay((_, delay) => Effect2.sync(() => {
|
|
496
|
+
const millis = Duration.toMillis(delay);
|
|
497
|
+
return Duration.millis(millis + Math.random() * millis);
|
|
498
|
+
})));
|
|
383
499
|
}
|
|
384
|
-
|
|
385
|
-
|
|
500
|
+
policy = policy.pipe(Schedule.modifyDelay((_, delay) => Effect2.succeed(capDelay(delay))));
|
|
501
|
+
const capped = Schedule.both(policy, Schedule.recurs(config.maxRetries));
|
|
502
|
+
return capped.pipe(Schedule.map(([delay]) => Effect2.succeed(delay)));
|
|
386
503
|
};
|
|
387
504
|
var FetchHttpClient = (retryConfig = defaultRetryConfig) => ({
|
|
388
505
|
retryConfig,
|
|
@@ -470,58 +587,42 @@ var FetchHttpClient = (retryConfig = defaultRetryConfig) => ({
|
|
|
470
587
|
});
|
|
471
588
|
var HttpClientLive = Layer2.succeed(HttpClient, FetchHttpClient());
|
|
472
589
|
var makeHttpClientLayer = (retryConfig) => Layer2.succeed(HttpClient, FetchHttpClient({ ...defaultRetryConfig, ...retryConfig }));
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
setVideo: () => setVideo,
|
|
477
|
-
setURL: () => setURL,
|
|
478
|
-
setTitle: () => setTitle,
|
|
479
|
-
setTimestamp: () => setTimestamp,
|
|
480
|
-
setThumbnail: () => setThumbnail,
|
|
481
|
-
setProvider: () => setProvider,
|
|
482
|
-
setImage: () => setImage,
|
|
483
|
-
setFooter: () => setFooter,
|
|
484
|
-
setFields: () => setFields,
|
|
485
|
-
setDescription: () => setDescription,
|
|
486
|
-
setColor: () => setColor,
|
|
487
|
-
setAuthor: () => setAuthor,
|
|
488
|
-
make: () => make,
|
|
489
|
-
buildDirect: () => buildDirect,
|
|
490
|
-
build: () => build,
|
|
491
|
-
addFieldImpl: () => addFieldImpl,
|
|
492
|
-
addFieldDirect: () => addFieldDirect,
|
|
493
|
-
addField: () => addField
|
|
590
|
+
var makeTestHttpClient = (resolver, retryConfig = defaultRetryConfig) => Layer2.succeed(HttpClient, {
|
|
591
|
+
request: resolver,
|
|
592
|
+
retryConfig
|
|
494
593
|
});
|
|
495
|
-
|
|
594
|
+
// src/layers/Default.ts
|
|
595
|
+
import { Layer as Layer4 } from "effect";
|
|
596
|
+
|
|
597
|
+
// src/services/WebhookService.ts
|
|
598
|
+
import {
|
|
599
|
+
Duration as Duration2,
|
|
600
|
+
Effect as Effect3,
|
|
601
|
+
Layer as Layer3,
|
|
602
|
+
pipe,
|
|
603
|
+
Schedule as Schedule2,
|
|
604
|
+
Schema as Schema6,
|
|
605
|
+
ServiceMap as ServiceMap3
|
|
606
|
+
} from "effect";
|
|
496
607
|
|
|
497
608
|
// src/schemas/Common.ts
|
|
498
609
|
import { Schema as Schema2 } from "effect";
|
|
499
|
-
var maxLength = (max) => Schema2.String.
|
|
500
|
-
var positiveInt = Schema2.Number.
|
|
501
|
-
var UrlString = Schema2.String.pipe(Schema2.
|
|
610
|
+
var maxLength = (max) => Schema2.String.check(Schema2.isMaxLength(max));
|
|
611
|
+
var positiveInt = Schema2.Number.check(Schema2.isInt(), Schema2.isGreaterThan(0));
|
|
612
|
+
var UrlString = Schema2.String.pipe(Schema2.check(Schema2.makeFilter((value) => {
|
|
502
613
|
try {
|
|
503
|
-
new URL(
|
|
614
|
+
new URL(value);
|
|
504
615
|
return true;
|
|
505
616
|
} catch {
|
|
506
|
-
return
|
|
617
|
+
return "Invalid URL format";
|
|
507
618
|
}
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
}));
|
|
511
|
-
var ISO8601Timestamp = Schema2.String.pipe(Schema2.filter((s) => {
|
|
619
|
+
})));
|
|
620
|
+
var ISO8601Timestamp = Schema2.String.pipe(Schema2.check(Schema2.makeFilter((value) => {
|
|
512
621
|
const iso8601Regex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z?$/;
|
|
513
|
-
return iso8601Regex.test(
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
var ColorCode = Schema2.Number.pipe(Schema2.int(), Schema2.greaterThanOrEqualTo(0), Schema2.lessThanOrEqualTo(16777215));
|
|
518
|
-
var Uint8ArraySchema = Schema2.instanceOf(Uint8Array).pipe(Schema2.annotations({
|
|
519
|
-
arbitrary: () => (fc) => fc.uint8Array().map((u8) => {
|
|
520
|
-
const ab = new ArrayBuffer(u8.byteLength);
|
|
521
|
-
new Uint8Array(ab).set(u8);
|
|
522
|
-
return new Uint8Array(ab);
|
|
523
|
-
})
|
|
524
|
-
}));
|
|
622
|
+
return iso8601Regex.test(value) ? true : "Invalid ISO8601 timestamp format";
|
|
623
|
+
})));
|
|
624
|
+
var ColorCode = Schema2.Number.check(Schema2.isInt(), Schema2.isGreaterThanOrEqualTo(0), Schema2.isLessThanOrEqualTo(16777215));
|
|
625
|
+
var Uint8ArraySchema = Schema2.instanceOf(Uint8Array);
|
|
525
626
|
|
|
526
627
|
// src/schemas/Embed.ts
|
|
527
628
|
import { Schema as Schema4 } from "effect";
|
|
@@ -531,222 +632,417 @@ import { Schema as Schema3 } from "effect";
|
|
|
531
632
|
class Field extends Schema3.Class("Field")({
|
|
532
633
|
name: maxLength(256),
|
|
533
634
|
value: maxLength(1024),
|
|
534
|
-
inline: Schema3.
|
|
635
|
+
inline: Schema3.optionalKey(Schema3.Boolean)
|
|
535
636
|
}) {
|
|
536
637
|
}
|
|
537
|
-
var FieldArray = Schema3.Array(Field).pipe(Schema3.
|
|
638
|
+
var FieldArray = Schema3.Array(Field).pipe(Schema3.check(Schema3.isMaxLength(25)));
|
|
538
639
|
|
|
539
640
|
// src/schemas/Embed.ts
|
|
540
641
|
class Attachment extends Schema4.Class("Attachment")({
|
|
541
642
|
url: Schema4.String,
|
|
542
|
-
proxyUrl: Schema4.
|
|
543
|
-
filename: Schema4.
|
|
544
|
-
size: Schema4.
|
|
545
|
-
height: Schema4.
|
|
546
|
-
width: Schema4.
|
|
643
|
+
proxyUrl: Schema4.optionalKey(Schema4.String),
|
|
644
|
+
filename: Schema4.optionalKey(Schema4.String),
|
|
645
|
+
size: Schema4.optionalKey(positiveInt),
|
|
646
|
+
height: Schema4.optionalKey(positiveInt),
|
|
647
|
+
width: Schema4.optionalKey(positiveInt)
|
|
547
648
|
}) {
|
|
548
649
|
}
|
|
549
|
-
var UrlOrAttachment = Schema4.Union(UrlString, Attachment);
|
|
650
|
+
var UrlOrAttachment = Schema4.Union([UrlString, Attachment]);
|
|
550
651
|
|
|
551
652
|
class Author extends Schema4.Class("Author")({
|
|
552
|
-
name: Schema4.
|
|
553
|
-
url: Schema4.
|
|
554
|
-
icon_url: Schema4.
|
|
555
|
-
proxy_icon_url: Schema4.
|
|
653
|
+
name: Schema4.optionalKey(maxLength(256)),
|
|
654
|
+
url: Schema4.optionalKey(UrlString),
|
|
655
|
+
icon_url: Schema4.optionalKey(UrlOrAttachment),
|
|
656
|
+
proxy_icon_url: Schema4.optionalKey(Schema4.String)
|
|
556
657
|
}) {
|
|
557
658
|
}
|
|
558
659
|
|
|
559
660
|
class Footer extends Schema4.Class("Footer")({
|
|
560
661
|
text: maxLength(2048),
|
|
561
|
-
icon_url: Schema4.
|
|
562
|
-
proxy_icon_url: Schema4.
|
|
662
|
+
icon_url: Schema4.optionalKey(UrlOrAttachment),
|
|
663
|
+
proxy_icon_url: Schema4.optionalKey(Schema4.String)
|
|
563
664
|
}) {
|
|
564
665
|
}
|
|
565
666
|
|
|
566
667
|
class Image extends Schema4.Class("Image")({
|
|
567
668
|
url: UrlOrAttachment,
|
|
568
|
-
proxy_url: Schema4.
|
|
569
|
-
height: Schema4.
|
|
570
|
-
width: Schema4.
|
|
669
|
+
proxy_url: Schema4.optionalKey(Schema4.String),
|
|
670
|
+
height: Schema4.optionalKey(positiveInt),
|
|
671
|
+
width: Schema4.optionalKey(positiveInt)
|
|
571
672
|
}) {
|
|
572
673
|
}
|
|
573
674
|
|
|
574
675
|
class Thumbnail extends Schema4.Class("Thumbnail")({
|
|
575
676
|
url: UrlOrAttachment,
|
|
576
|
-
proxy_url: Schema4.
|
|
577
|
-
height: Schema4.
|
|
578
|
-
width: Schema4.
|
|
677
|
+
proxy_url: Schema4.optionalKey(Schema4.String),
|
|
678
|
+
height: Schema4.optionalKey(positiveInt),
|
|
679
|
+
width: Schema4.optionalKey(positiveInt)
|
|
579
680
|
}) {
|
|
580
681
|
}
|
|
581
682
|
|
|
582
683
|
class Video extends Schema4.Class("Video")({
|
|
583
|
-
url: Schema4.
|
|
584
|
-
proxy_url: Schema4.
|
|
585
|
-
height: Schema4.
|
|
586
|
-
width: Schema4.
|
|
684
|
+
url: Schema4.optionalKey(UrlString),
|
|
685
|
+
proxy_url: Schema4.optionalKey(Schema4.String),
|
|
686
|
+
height: Schema4.optionalKey(positiveInt),
|
|
687
|
+
width: Schema4.optionalKey(positiveInt)
|
|
587
688
|
}) {
|
|
588
689
|
}
|
|
589
690
|
|
|
590
691
|
class Provider extends Schema4.Class("Provider")({
|
|
591
|
-
name: Schema4.
|
|
592
|
-
url: Schema4.
|
|
692
|
+
name: Schema4.optionalKey(Schema4.String),
|
|
693
|
+
url: Schema4.optionalKey(UrlString)
|
|
593
694
|
}) {
|
|
594
695
|
}
|
|
595
696
|
|
|
596
697
|
class Embed extends Schema4.Class("Embed")({
|
|
597
|
-
title: Schema4.
|
|
598
|
-
type: Schema4.
|
|
599
|
-
url: Schema4.
|
|
600
|
-
description: Schema4.
|
|
601
|
-
timestamp: Schema4.
|
|
602
|
-
color: Schema4.
|
|
603
|
-
footer: Schema4.
|
|
604
|
-
image: Schema4.
|
|
605
|
-
thumbnail: Schema4.
|
|
606
|
-
video: Schema4.
|
|
607
|
-
provider: Schema4.
|
|
608
|
-
author: Schema4.
|
|
609
|
-
fields: Schema4.
|
|
698
|
+
title: Schema4.optionalKey(maxLength(256)),
|
|
699
|
+
type: Schema4.optionalKey(Schema4.Literal("rich")),
|
|
700
|
+
url: Schema4.optionalKey(UrlString),
|
|
701
|
+
description: Schema4.optionalKey(maxLength(4096)),
|
|
702
|
+
timestamp: Schema4.optionalKey(ISO8601Timestamp),
|
|
703
|
+
color: Schema4.optionalKey(ColorCode),
|
|
704
|
+
footer: Schema4.optionalKey(Footer),
|
|
705
|
+
image: Schema4.optionalKey(Image),
|
|
706
|
+
thumbnail: Schema4.optionalKey(Thumbnail),
|
|
707
|
+
video: Schema4.optionalKey(Video),
|
|
708
|
+
provider: Schema4.optionalKey(Provider),
|
|
709
|
+
author: Schema4.optionalKey(Author),
|
|
710
|
+
fields: Schema4.optionalKey(FieldArray)
|
|
610
711
|
}) {
|
|
611
712
|
}
|
|
612
|
-
var EmbedArray = Schema4.Array(Embed).pipe(Schema4.
|
|
713
|
+
var EmbedArray = Schema4.Array(Embed).pipe(Schema4.check(Schema4.isMaxLength(10)));
|
|
613
714
|
|
|
614
715
|
// src/schemas/Webhook.ts
|
|
615
716
|
import { Schema as Schema5 } from "effect";
|
|
616
|
-
var WebhookFile = Schema5.Union(
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
717
|
+
var WebhookFile = Schema5.Union([
|
|
718
|
+
Schema5.String,
|
|
719
|
+
Attachment,
|
|
720
|
+
Schema5.Struct({
|
|
721
|
+
name: Schema5.String,
|
|
722
|
+
data: Schema5.Union([Schema5.String, Uint8ArraySchema])
|
|
723
|
+
})
|
|
724
|
+
]);
|
|
620
725
|
|
|
621
726
|
class Webhook extends Schema5.Class("Webhook")({
|
|
622
|
-
username: Schema5.
|
|
623
|
-
avatar_url: Schema5.
|
|
624
|
-
tts: Schema5.
|
|
625
|
-
content: Schema5.
|
|
626
|
-
file: Schema5.
|
|
627
|
-
embeds: Schema5.
|
|
727
|
+
username: Schema5.optionalKey(maxLength(80)),
|
|
728
|
+
avatar_url: Schema5.optionalKey(UrlString),
|
|
729
|
+
tts: Schema5.optionalKey(Schema5.Boolean),
|
|
730
|
+
content: Schema5.optionalKey(maxLength(2000)),
|
|
731
|
+
file: Schema5.optionalKey(WebhookFile),
|
|
732
|
+
embeds: Schema5.optionalKey(EmbedArray)
|
|
628
733
|
}) {
|
|
629
734
|
}
|
|
630
735
|
|
|
631
736
|
class WebhookParameter extends Schema5.Class("WebhookParameter")({
|
|
632
|
-
name: Schema5.
|
|
633
|
-
avatar: Schema5.
|
|
634
|
-
channel_id: Schema5.
|
|
737
|
+
name: Schema5.optionalKey(maxLength(80)),
|
|
738
|
+
avatar: Schema5.optionalKey(UrlString),
|
|
739
|
+
channel_id: Schema5.optionalKey(Schema5.String)
|
|
635
740
|
}) {
|
|
636
741
|
}
|
|
637
742
|
|
|
638
743
|
class WebhookResponse extends Schema5.Class("WebhookResponse")({
|
|
639
744
|
id: Schema5.String,
|
|
640
745
|
type: Schema5.Number,
|
|
641
|
-
guild_id: Schema5.
|
|
746
|
+
guild_id: Schema5.optionalKey(Schema5.String),
|
|
642
747
|
channel_id: Schema5.String,
|
|
643
|
-
user: Schema5.
|
|
748
|
+
user: Schema5.optionalKey(Schema5.Struct({
|
|
644
749
|
id: Schema5.String,
|
|
645
750
|
username: Schema5.String,
|
|
646
|
-
avatar: Schema5.
|
|
751
|
+
avatar: Schema5.optionalKey(Schema5.String),
|
|
647
752
|
discriminator: Schema5.String,
|
|
648
|
-
public_flags: Schema5.
|
|
753
|
+
public_flags: Schema5.optionalKey(Schema5.Number)
|
|
649
754
|
})),
|
|
650
|
-
name: Schema5.
|
|
651
|
-
avatar: Schema5.
|
|
652
|
-
token: Schema5.
|
|
653
|
-
application_id: Schema5.
|
|
654
|
-
source_guild: Schema5.
|
|
755
|
+
name: Schema5.optionalKey(Schema5.String),
|
|
756
|
+
avatar: Schema5.optionalKey(Schema5.String),
|
|
757
|
+
token: Schema5.optionalKey(Schema5.String),
|
|
758
|
+
application_id: Schema5.optionalKey(Schema5.String),
|
|
759
|
+
source_guild: Schema5.optionalKey(Schema5.Struct({
|
|
655
760
|
id: Schema5.String,
|
|
656
761
|
name: Schema5.String,
|
|
657
|
-
icon: Schema5.
|
|
762
|
+
icon: Schema5.optionalKey(Schema5.String)
|
|
658
763
|
})),
|
|
659
|
-
source_channel: Schema5.
|
|
764
|
+
source_channel: Schema5.optionalKey(Schema5.Struct({
|
|
660
765
|
id: Schema5.String,
|
|
661
766
|
name: Schema5.String
|
|
662
767
|
})),
|
|
663
|
-
url: Schema5.
|
|
768
|
+
url: Schema5.optionalKey(UrlString)
|
|
664
769
|
}) {
|
|
665
770
|
}
|
|
666
771
|
|
|
772
|
+
// src/utils/normalize.ts
|
|
773
|
+
var stripUndefined = (input) => {
|
|
774
|
+
if (Array.isArray(input)) {
|
|
775
|
+
return input.map(stripUndefined);
|
|
776
|
+
}
|
|
777
|
+
if (input && typeof input === "object") {
|
|
778
|
+
const proto = Object.getPrototypeOf(input);
|
|
779
|
+
if (proto !== Object.prototype && proto !== null) {
|
|
780
|
+
return input;
|
|
781
|
+
}
|
|
782
|
+
const entries = Object.entries(input).filter(([, value]) => value !== undefined).map(([key, value]) => [key, stripUndefined(value)]);
|
|
783
|
+
return Object.fromEntries(entries);
|
|
784
|
+
}
|
|
785
|
+
return input;
|
|
786
|
+
};
|
|
787
|
+
|
|
788
|
+
// src/services/WebhookService.ts
|
|
789
|
+
class WebhookService extends ServiceMap3.Service()("WebhookService") {
|
|
790
|
+
}
|
|
791
|
+
var makeWebhookService = Effect3.gen(function* () {
|
|
792
|
+
const config = yield* Config;
|
|
793
|
+
const httpClient = yield* HttpClient;
|
|
794
|
+
const webhookUrl = config.webhook.webhookUrl;
|
|
795
|
+
const retrySchedule = createRetrySchedule({
|
|
796
|
+
maxRetries: config.webhook.maxRetries ?? httpClient.retryConfig.maxRetries,
|
|
797
|
+
baseDelay: Duration2.millis(config.webhook.baseDelayMs ?? Duration2.toMillis(httpClient.retryConfig.baseDelay)),
|
|
798
|
+
maxDelay: Duration2.millis(config.webhook.maxDelayMs ?? Duration2.toMillis(httpClient.retryConfig.maxDelay)),
|
|
799
|
+
jitter: config.webhook.enableJitter ?? httpClient.retryConfig.jitter
|
|
800
|
+
});
|
|
801
|
+
const sendWebhookRaw = (webhook) => pipe(Schema6.decodeUnknownEffect(Webhook)(stripUndefined(webhook)), Effect3.mapError((e) => ValidationError.fromParseError(e, { field: "webhook", value: webhook })), Effect3.flatMap((validatedWebhook) => httpClient.request({
|
|
802
|
+
method: "POST",
|
|
803
|
+
url: webhookUrl,
|
|
804
|
+
body: validatedWebhook
|
|
805
|
+
}).pipe(Effect3.retry(Schedule2.while(retrySchedule, (meta) => Effect3.succeed(meta.input instanceof NetworkError || meta.input instanceof RateLimitError || meta.input instanceof HttpError && (meta.input.response?.status ?? 0) >= 500))))), Effect3.map((response) => ({
|
|
806
|
+
status: response.status,
|
|
807
|
+
ok: response.status >= 200 && response.status < 300,
|
|
808
|
+
headers: response.headers,
|
|
809
|
+
body: response.body,
|
|
810
|
+
text: response.text
|
|
811
|
+
})));
|
|
812
|
+
const sendWebhook = (webhook) => pipe(sendWebhookRaw(webhook), Effect3.flatMap((response) => response.status === 204 && response.text === "" ? Effect3.void : Effect3.fail(new WebhookError({
|
|
813
|
+
message: `Unexpected webhook response: ${response.status}`,
|
|
814
|
+
cause: response
|
|
815
|
+
}))));
|
|
816
|
+
const modifyWebhook = (params) => pipe(Schema6.decodeUnknownEffect(WebhookParameter)(stripUndefined(params)), Effect3.mapError((e) => ValidationError.fromParseError(e, { field: "params", value: params })), Effect3.flatMap((validatedParams) => httpClient.request({
|
|
817
|
+
method: "PATCH",
|
|
818
|
+
url: webhookUrl,
|
|
819
|
+
body: validatedParams
|
|
820
|
+
})), Effect3.flatMap((response) => Schema6.decodeUnknownEffect(WebhookResponse)(response.body).pipe(Effect3.mapError(() => new WebhookError({
|
|
821
|
+
message: "Invalid webhook response",
|
|
822
|
+
cause: response.body
|
|
823
|
+
})))));
|
|
824
|
+
const getWebhook = () => pipe(httpClient.request({
|
|
825
|
+
method: "GET",
|
|
826
|
+
url: webhookUrl
|
|
827
|
+
}), Effect3.flatMap((response) => Schema6.decodeUnknownEffect(WebhookResponse)(response.body).pipe(Effect3.mapError(() => new WebhookError({
|
|
828
|
+
message: "Invalid webhook response",
|
|
829
|
+
cause: response.body
|
|
830
|
+
})))));
|
|
831
|
+
const validateWebhook = () => pipe(httpClient.request({
|
|
832
|
+
method: "GET",
|
|
833
|
+
url: webhookUrl
|
|
834
|
+
}), Effect3.as(true), Effect3.catch(() => Effect3.succeed(false)));
|
|
835
|
+
const deleteWebhook = () => pipe(httpClient.request({
|
|
836
|
+
method: "DELETE",
|
|
837
|
+
url: webhookUrl
|
|
838
|
+
}), Effect3.map((response) => response.status === 204));
|
|
839
|
+
return {
|
|
840
|
+
sendWebhook,
|
|
841
|
+
sendWebhookRaw,
|
|
842
|
+
modifyWebhook,
|
|
843
|
+
getWebhook,
|
|
844
|
+
deleteWebhook,
|
|
845
|
+
validateWebhook
|
|
846
|
+
};
|
|
847
|
+
});
|
|
848
|
+
var WebhookServiceLive = Layer3.effect(WebhookService, makeWebhookService);
|
|
849
|
+
var sendWebhook = (webhook) => WebhookService.use((service) => service.sendWebhook(webhook));
|
|
850
|
+
var sendWebhookRaw = (webhook) => WebhookService.use((service) => service.sendWebhookRaw(webhook));
|
|
851
|
+
var modifyWebhook = (params) => WebhookService.use((service) => service.modifyWebhook(params));
|
|
852
|
+
var getWebhook = () => WebhookService.use((service) => service.getWebhook());
|
|
853
|
+
var deleteWebhook = () => WebhookService.use((service) => service.deleteWebhook());
|
|
854
|
+
var validateWebhook = () => WebhookService.use((service) => service.validateWebhook());
|
|
855
|
+
|
|
856
|
+
// src/layers/Default.ts
|
|
857
|
+
var makeDefaultLayer = (url, options) => WebhookServiceLive.pipe(Layer4.provide(makeConfigLayer(url, options)), Layer4.provide(HttpClientLive));
|
|
667
858
|
// src/pipes/Embed.ts
|
|
859
|
+
var exports_Embed = {};
|
|
860
|
+
__export(exports_Embed, {
|
|
861
|
+
setVideo: () => setVideo,
|
|
862
|
+
setURL: () => setURL,
|
|
863
|
+
setTitle: () => setTitle,
|
|
864
|
+
setTimestamp: () => setTimestamp,
|
|
865
|
+
setThumbnail: () => setThumbnail,
|
|
866
|
+
setProvider: () => setProvider,
|
|
867
|
+
setImage: () => setImage,
|
|
868
|
+
setFooter: () => setFooter,
|
|
869
|
+
setFields: () => setFields,
|
|
870
|
+
setDescription: () => setDescription,
|
|
871
|
+
setColor: () => setColor,
|
|
872
|
+
setAuthor: () => setAuthor,
|
|
873
|
+
make: () => make,
|
|
874
|
+
buildDirect: () => buildDirect,
|
|
875
|
+
build: () => build,
|
|
876
|
+
addFieldImpl: () => addFieldImpl,
|
|
877
|
+
addFieldDirect: () => addFieldDirect,
|
|
878
|
+
addField: () => addField
|
|
879
|
+
});
|
|
880
|
+
import { Effect as Effect4, pipe as pipe2, Schema as Schema7 } from "effect";
|
|
668
881
|
var createDraft = () => ({});
|
|
669
|
-
var setTitleImpl = (title) => (d) =>
|
|
882
|
+
var setTitleImpl = (title) => (d) => pipe2(Schema7.decodeUnknownEffect(maxLength(256))(title), Effect4.mapError(() => ValidationError.fromIssue("title", "Title must be 256 characters or less", {
|
|
670
883
|
constraint: "MaxLength",
|
|
671
884
|
expected: "256 characters or less",
|
|
672
885
|
actual: title.length
|
|
673
|
-
})),
|
|
674
|
-
var setURLImpl = (url) => (d) =>
|
|
886
|
+
})), Effect4.as({ ...d, title }));
|
|
887
|
+
var setURLImpl = (url) => (d) => pipe2(Schema7.decodeUnknownEffect(UrlString)(url), Effect4.mapError(() => ValidationError.fromIssue("url", "Invalid URL", {
|
|
675
888
|
constraint: "URL",
|
|
676
889
|
expected: "valid URL",
|
|
677
890
|
actual: url
|
|
678
|
-
})),
|
|
679
|
-
var setDescriptionImpl = (description) => (d) =>
|
|
891
|
+
})), Effect4.as({ ...d, url }));
|
|
892
|
+
var setDescriptionImpl = (description) => (d) => pipe2(Schema7.decodeUnknownEffect(maxLength(4096))(description), Effect4.mapError(() => ValidationError.fromIssue("description", "Description must be 4096 characters or less", {
|
|
680
893
|
constraint: "MaxLength",
|
|
681
894
|
expected: "4096 characters or less",
|
|
682
895
|
actual: description.length
|
|
683
|
-
})),
|
|
684
|
-
var setTimestampImpl = (date) => (d) =>
|
|
896
|
+
})), Effect4.as({ ...d, description }));
|
|
897
|
+
var setTimestampImpl = (date) => (d) => Effect4.succeed({ ...d, timestamp: (date ?? new Date).toISOString() });
|
|
685
898
|
var setColorImpl = (color) => (d) => {
|
|
686
899
|
const colorValue = typeof color === "string" ? parseInt(color.replace("#", ""), 16) : color;
|
|
687
|
-
return
|
|
900
|
+
return pipe2(Schema7.decodeUnknownEffect(ColorCode)(colorValue), Effect4.mapError(() => ValidationError.fromIssue("color", "Invalid color code (must be 0-16777215)", {
|
|
688
901
|
constraint: "Range",
|
|
689
902
|
expected: "0-16777215",
|
|
690
903
|
actual: colorValue
|
|
691
|
-
})),
|
|
904
|
+
})), Effect4.as({ ...d, color: colorValue }));
|
|
692
905
|
};
|
|
693
906
|
var setFooterImpl = (footerOrText, icon_url, proxy_icon_url) => (d) => {
|
|
694
|
-
const footer = typeof footerOrText === "string" ? {
|
|
695
|
-
|
|
907
|
+
const footer = typeof footerOrText === "string" ? {
|
|
908
|
+
text: footerOrText,
|
|
909
|
+
...icon_url === undefined ? {} : { icon_url },
|
|
910
|
+
...proxy_icon_url === undefined ? {} : { proxy_icon_url }
|
|
911
|
+
} : (() => {
|
|
912
|
+
const { text, icon_url: icon_url2, proxy_icon_url: proxy_icon_url2 } = footerOrText;
|
|
913
|
+
return {
|
|
914
|
+
text,
|
|
915
|
+
...icon_url2 === undefined ? {} : { icon_url: icon_url2 },
|
|
916
|
+
...proxy_icon_url2 === undefined ? {} : { proxy_icon_url: proxy_icon_url2 }
|
|
917
|
+
};
|
|
918
|
+
})();
|
|
919
|
+
return pipe2(Schema7.decodeUnknownEffect(Footer)(footer), Effect4.mapError((e) => ValidationError.fromParseError(e, { field: "footer", value: footer })), Effect4.as({ ...d, footer }));
|
|
696
920
|
};
|
|
697
921
|
var setImageImpl = (imageOrUrl, height, width) => (d) => {
|
|
698
|
-
const image = typeof imageOrUrl === "string" ? {
|
|
699
|
-
|
|
922
|
+
const image = typeof imageOrUrl === "string" ? {
|
|
923
|
+
url: imageOrUrl,
|
|
924
|
+
...height === undefined ? {} : { height },
|
|
925
|
+
...width === undefined ? {} : { width }
|
|
926
|
+
} : (() => {
|
|
927
|
+
const { url, proxy_url, height: height2, width: width2 } = imageOrUrl;
|
|
928
|
+
return {
|
|
929
|
+
url,
|
|
930
|
+
...proxy_url === undefined ? {} : { proxy_url },
|
|
931
|
+
...height2 === undefined ? {} : { height: height2 },
|
|
932
|
+
...width2 === undefined ? {} : { width: width2 }
|
|
933
|
+
};
|
|
934
|
+
})();
|
|
935
|
+
return pipe2(Schema7.decodeUnknownEffect(Image)(image), Effect4.mapError((e) => ValidationError.fromParseError(e, { field: "image", value: image })), Effect4.as({ ...d, image }));
|
|
700
936
|
};
|
|
701
937
|
var setThumbnailImpl = (thumbnailOrUrl, height, width) => (d) => {
|
|
702
|
-
const thumbnail = typeof thumbnailOrUrl === "string" ? {
|
|
703
|
-
|
|
938
|
+
const thumbnail = typeof thumbnailOrUrl === "string" ? {
|
|
939
|
+
url: thumbnailOrUrl,
|
|
940
|
+
...height === undefined ? {} : { height },
|
|
941
|
+
...width === undefined ? {} : { width }
|
|
942
|
+
} : (() => {
|
|
943
|
+
const { url, proxy_url, height: height2, width: width2 } = thumbnailOrUrl;
|
|
944
|
+
return {
|
|
945
|
+
url,
|
|
946
|
+
...proxy_url === undefined ? {} : { proxy_url },
|
|
947
|
+
...height2 === undefined ? {} : { height: height2 },
|
|
948
|
+
...width2 === undefined ? {} : { width: width2 }
|
|
949
|
+
};
|
|
950
|
+
})();
|
|
951
|
+
return pipe2(Schema7.decodeUnknownEffect(Thumbnail)(thumbnail), Effect4.mapError((e) => ValidationError.fromParseError(e, {
|
|
704
952
|
field: "thumbnail",
|
|
705
953
|
value: thumbnail
|
|
706
|
-
})),
|
|
954
|
+
})), Effect4.as({ ...d, thumbnail }));
|
|
707
955
|
};
|
|
708
956
|
var setVideoImpl = (videoOrUrl, height, width) => (d) => {
|
|
709
|
-
const video = typeof videoOrUrl === "string" ? {
|
|
710
|
-
|
|
957
|
+
const video = typeof videoOrUrl === "string" ? {
|
|
958
|
+
url: videoOrUrl,
|
|
959
|
+
...height === undefined ? {} : { height },
|
|
960
|
+
...width === undefined ? {} : { width }
|
|
961
|
+
} : (() => {
|
|
962
|
+
const { url, proxy_url, height: height2, width: width2 } = videoOrUrl;
|
|
963
|
+
return {
|
|
964
|
+
...url === undefined ? {} : { url },
|
|
965
|
+
...proxy_url === undefined ? {} : { proxy_url },
|
|
966
|
+
...height2 === undefined ? {} : { height: height2 },
|
|
967
|
+
...width2 === undefined ? {} : { width: width2 }
|
|
968
|
+
};
|
|
969
|
+
})();
|
|
970
|
+
return pipe2(Schema7.decodeUnknownEffect(Video)(video), Effect4.mapError((e) => ValidationError.fromParseError(e, { field: "video", value: video })), Effect4.as({ ...d, video }));
|
|
711
971
|
};
|
|
712
972
|
var setProviderImpl = (providerOrName, url) => (d) => {
|
|
713
|
-
const provider = typeof providerOrName === "string" ? {
|
|
714
|
-
|
|
973
|
+
const provider = typeof providerOrName === "string" ? {
|
|
974
|
+
name: providerOrName,
|
|
975
|
+
...url === undefined ? {} : { url }
|
|
976
|
+
} : (() => {
|
|
977
|
+
const { name, url: url2 } = providerOrName;
|
|
978
|
+
return {
|
|
979
|
+
...name === undefined ? {} : { name },
|
|
980
|
+
...url2 === undefined ? {} : { url: url2 }
|
|
981
|
+
};
|
|
982
|
+
})();
|
|
983
|
+
return pipe2(Schema7.decodeUnknownEffect(Provider)(provider), Effect4.mapError((e) => ValidationError.fromParseError(e, {
|
|
715
984
|
field: "provider",
|
|
716
985
|
value: provider
|
|
717
|
-
})),
|
|
986
|
+
})), Effect4.as({ ...d, provider }));
|
|
718
987
|
};
|
|
719
988
|
var setAuthorImpl = (authorOrName, url, icon_url) => (d) => {
|
|
720
|
-
const author = typeof authorOrName === "string" ? {
|
|
721
|
-
|
|
989
|
+
const author = typeof authorOrName === "string" ? {
|
|
990
|
+
name: authorOrName,
|
|
991
|
+
...url === undefined ? {} : { url },
|
|
992
|
+
...icon_url === undefined ? {} : { icon_url }
|
|
993
|
+
} : (() => {
|
|
994
|
+
const { name, url: url2, icon_url: icon_url2, proxy_icon_url } = authorOrName;
|
|
995
|
+
return {
|
|
996
|
+
...name === undefined ? {} : { name },
|
|
997
|
+
...url2 === undefined ? {} : { url: url2 },
|
|
998
|
+
...icon_url2 === undefined ? {} : { icon_url: icon_url2 },
|
|
999
|
+
...proxy_icon_url === undefined ? {} : { proxy_icon_url }
|
|
1000
|
+
};
|
|
1001
|
+
})();
|
|
1002
|
+
return pipe2(Schema7.decodeUnknownEffect(Author)(author), Effect4.mapError((e) => ValidationError.fromParseError(e, { field: "author", value: author })), Effect4.as({ ...d, author }));
|
|
722
1003
|
};
|
|
723
1004
|
var addFieldImpl = (fieldOrName, value, inline = false) => (d) => {
|
|
724
1005
|
const currentFields = d.fields || [];
|
|
725
1006
|
if (currentFields.length >= 25) {
|
|
726
|
-
return
|
|
1007
|
+
return Effect4.fail(ValidationError.fromIssue("fields", "Cannot add more than 25 fields", {
|
|
727
1008
|
constraint: "MaxItems",
|
|
728
1009
|
expected: "25 fields or less",
|
|
729
1010
|
actual: currentFields.length + 1
|
|
730
1011
|
}));
|
|
731
1012
|
}
|
|
732
|
-
const field = typeof fieldOrName === "string" ? { name: fieldOrName, value: value ?? "", inline } :
|
|
733
|
-
|
|
1013
|
+
const field = typeof fieldOrName === "string" ? { name: fieldOrName, value: value ?? "", inline } : (() => {
|
|
1014
|
+
const { name, value: value2, inline: inline2 } = fieldOrName;
|
|
1015
|
+
return {
|
|
1016
|
+
name,
|
|
1017
|
+
value: value2,
|
|
1018
|
+
...inline2 === undefined ? {} : { inline: inline2 }
|
|
1019
|
+
};
|
|
1020
|
+
})();
|
|
1021
|
+
return pipe2(Schema7.decodeUnknownEffect(Field)(field), Effect4.mapError((e) => ValidationError.fromParseError(e, { field: "fields", value: field })), Effect4.map(() => ({ ...d, fields: [...currentFields, field] })));
|
|
734
1022
|
};
|
|
735
1023
|
var setFieldsImpl = (fields) => (d) => {
|
|
736
1024
|
if (fields.length > 25) {
|
|
737
|
-
return
|
|
1025
|
+
return Effect4.fail(ValidationError.fromIssue("fields", "Cannot have more than 25 fields", {
|
|
738
1026
|
constraint: "MaxItems",
|
|
739
1027
|
expected: "25 fields or less",
|
|
740
1028
|
actual: fields.length
|
|
741
1029
|
}));
|
|
742
1030
|
}
|
|
743
|
-
|
|
1031
|
+
const normalized = fields.map((field) => {
|
|
1032
|
+
const { name, value, inline } = field;
|
|
1033
|
+
return {
|
|
1034
|
+
name,
|
|
1035
|
+
value,
|
|
1036
|
+
...inline === undefined ? {} : { inline }
|
|
1037
|
+
};
|
|
1038
|
+
});
|
|
1039
|
+
return pipe2(Effect4.forEach(normalized, (f) => Schema7.decodeUnknownEffect(Field)(f)), Effect4.mapError((e) => ValidationError.fromParseError(e, { field: "fields", value: fields })), Effect4.map((decoded) => ({ ...d, fields: decoded })));
|
|
744
1040
|
};
|
|
745
|
-
var buildImpl = (d) =>
|
|
1041
|
+
var buildImpl = (d) => pipe2(Schema7.decodeUnknownEffect(Embed)(stripUndefined({ ...d, type: "rich" })), Effect4.mapError((e) => ValidationError.fromParseError(e, { field: "embed", value: d })));
|
|
746
1042
|
var buildDirect = buildImpl;
|
|
747
1043
|
var addFieldDirect = addFieldImpl;
|
|
748
|
-
var make =
|
|
749
|
-
var chain = (f) => (self) =>
|
|
1044
|
+
var make = Effect4.succeed(createDraft());
|
|
1045
|
+
var chain = (f) => (self) => pipe2(self, Effect4.flatMap(f));
|
|
750
1046
|
var setTitle = (title) => chain(setTitleImpl(title));
|
|
751
1047
|
var setURL = (url) => chain(setURLImpl(url));
|
|
752
1048
|
var setDescription = (description) => chain(setDescriptionImpl(description));
|
|
@@ -760,10 +1056,11 @@ var setProvider = (provider, url) => chain(setProviderImpl(provider, url));
|
|
|
760
1056
|
var setAuthor = (author, url, icon_url) => chain(setAuthorImpl(author, url, icon_url));
|
|
761
1057
|
var addField = (field, value, inline = false) => chain(addFieldImpl(field, value, inline));
|
|
762
1058
|
var setFields = (fields) => chain(setFieldsImpl(fields));
|
|
763
|
-
var build = (self) =>
|
|
1059
|
+
var build = (self) => pipe2(self, Effect4.flatMap(buildImpl));
|
|
764
1060
|
// src/pipes/Webhook.ts
|
|
765
1061
|
var exports_Webhook = {};
|
|
766
1062
|
__export(exports_Webhook, {
|
|
1063
|
+
validate: () => validate,
|
|
767
1064
|
setUsername: () => setUsername,
|
|
768
1065
|
setTTS: () => setTTS,
|
|
769
1066
|
setFile: () => setFile,
|
|
@@ -777,123 +1074,52 @@ __export(exports_Webhook, {
|
|
|
777
1074
|
addEmbedDirect: () => addEmbedDirect,
|
|
778
1075
|
addEmbed: () => addEmbed
|
|
779
1076
|
});
|
|
780
|
-
import { Effect as
|
|
1077
|
+
import { Effect as Effect5, pipe as pipe3, Schema as Schema8 } from "effect";
|
|
781
1078
|
var createDraft2 = () => ({});
|
|
782
|
-
var setUsernameImpl = (username) => (d) =>
|
|
1079
|
+
var setUsernameImpl = (username) => (d) => pipe3(Schema8.decodeUnknownEffect(maxLength(80))(username), Effect5.mapError(() => ValidationError.fromIssue("username", "Username must be 80 characters or less", {
|
|
783
1080
|
constraint: "MaxLength",
|
|
784
1081
|
expected: "80 characters or less",
|
|
785
1082
|
actual: username.length
|
|
786
|
-
})),
|
|
787
|
-
var setAvatarUrlImpl = (avatar_url) => (d) =>
|
|
1083
|
+
})), Effect5.as({ ...d, username }));
|
|
1084
|
+
var setAvatarUrlImpl = (avatar_url) => (d) => pipe3(Schema8.decodeUnknownEffect(UrlString)(avatar_url), Effect5.mapError(() => ValidationError.fromIssue("avatar_url", "Invalid avatar URL", {
|
|
788
1085
|
constraint: "URL",
|
|
789
1086
|
expected: "valid URL",
|
|
790
1087
|
actual: avatar_url
|
|
791
|
-
})),
|
|
792
|
-
var setContentImpl = (content) => (d) =>
|
|
1088
|
+
})), Effect5.as({ ...d, avatar_url }));
|
|
1089
|
+
var setContentImpl = (content) => (d) => pipe3(Schema8.decodeUnknownEffect(maxLength(2000))(content), Effect5.mapError(() => ValidationError.fromIssue("content", "Content must be 2000 characters or less", {
|
|
793
1090
|
constraint: "MaxLength",
|
|
794
1091
|
expected: "2000 characters or less",
|
|
795
1092
|
actual: content.length
|
|
796
|
-
})),
|
|
797
|
-
var setTTSImpl = (tts) => (d) =>
|
|
1093
|
+
})), Effect5.as({ ...d, content }));
|
|
1094
|
+
var setTTSImpl = (tts) => (d) => Effect5.succeed({ ...d, tts });
|
|
798
1095
|
var addEmbedImpl = (embed) => (d) => {
|
|
799
1096
|
const current = d.embeds || [];
|
|
800
1097
|
const next = [...current, embed];
|
|
801
|
-
return
|
|
1098
|
+
return pipe3(Schema8.decodeUnknownEffect(EmbedArray)(stripUndefined(next)), Effect5.mapError(() => ValidationError.fromIssue("embeds", "Cannot have more than 10 embeds", {
|
|
802
1099
|
constraint: "MaxItems",
|
|
803
1100
|
expected: "10 embeds or less",
|
|
804
1101
|
actual: next.length
|
|
805
|
-
})),
|
|
1102
|
+
})), Effect5.map((decoded) => ({ ...d, embeds: decoded })));
|
|
806
1103
|
};
|
|
807
|
-
var setFileImpl = (file) => (d) =>
|
|
808
|
-
var buildImpl2 = (d) =>
|
|
1104
|
+
var setFileImpl = (file) => (d) => Effect5.succeed({ ...d, file });
|
|
1105
|
+
var buildImpl2 = (d) => pipe3(Schema8.decodeUnknownEffect(Webhook)(stripUndefined(d)), Effect5.mapError((e) => ValidationError.fromParseError(e, { field: "webhook", value: d })));
|
|
809
1106
|
var buildDirect2 = buildImpl2;
|
|
810
1107
|
var addEmbedDirect = addEmbedImpl;
|
|
811
|
-
var
|
|
812
|
-
var
|
|
813
|
-
var
|
|
1108
|
+
var validate = (input) => pipe3(Schema8.decodeUnknownEffect(Webhook)(stripUndefined(input)), Effect5.mapError((e) => ValidationError.fromParseError(e, { field: "webhook", value: input })));
|
|
1109
|
+
var modifyParams = (p) => pipe3(Schema8.decodeUnknownEffect(WebhookParameter)(stripUndefined(p)), Effect5.mapError((e) => ValidationError.fromParseError(e, { field: "params", value: p })));
|
|
1110
|
+
var make2 = Effect5.succeed(createDraft2());
|
|
1111
|
+
var chain2 = (f) => (self) => pipe3(self, Effect5.flatMap(f));
|
|
814
1112
|
var setUsername = (username) => chain2(setUsernameImpl(username));
|
|
815
1113
|
var setAvatarUrl = (url) => chain2(setAvatarUrlImpl(url));
|
|
816
1114
|
var setContent = (content) => chain2(setContentImpl(content));
|
|
817
1115
|
var setTTS = (tts) => chain2(setTTSImpl(tts));
|
|
818
1116
|
var addEmbed = (embed) => chain2(addEmbedImpl(embed));
|
|
819
1117
|
var setFile = (file) => chain2(setFileImpl(file));
|
|
820
|
-
var build2 = (self) =>
|
|
821
|
-
// src/services/WebhookService.ts
|
|
822
|
-
import {
|
|
823
|
-
Context as Context3,
|
|
824
|
-
Duration as Duration2,
|
|
825
|
-
Effect as Effect5,
|
|
826
|
-
Layer as Layer3,
|
|
827
|
-
pipe as pipe3,
|
|
828
|
-
Schedule as Schedule2,
|
|
829
|
-
Schema as Schema8
|
|
830
|
-
} from "effect";
|
|
831
|
-
class WebhookService extends Context3.Tag("WebhookService")() {
|
|
832
|
-
}
|
|
833
|
-
var makeWebhookService = Effect5.gen(function* () {
|
|
834
|
-
const config = yield* Config;
|
|
835
|
-
const httpClient = yield* HttpClient;
|
|
836
|
-
const webhookUrl = config.webhook.webhookUrl;
|
|
837
|
-
const retrySchedule = createRetrySchedule({
|
|
838
|
-
maxRetries: config.webhook.maxRetries ?? httpClient.retryConfig.maxRetries,
|
|
839
|
-
baseDelay: Duration2.millis(config.webhook.baseDelayMs ?? Duration2.toMillis(httpClient.retryConfig.baseDelay)),
|
|
840
|
-
maxDelay: Duration2.millis(config.webhook.maxDelayMs ?? Duration2.toMillis(httpClient.retryConfig.maxDelay)),
|
|
841
|
-
jitter: config.webhook.enableJitter ?? httpClient.retryConfig.jitter
|
|
842
|
-
});
|
|
843
|
-
const sendWebhook = (webhook) => pipe3(Schema8.decodeUnknown(Webhook)(webhook), Effect5.mapError((e) => ValidationError.fromParseError(e, { field: "webhook", value: webhook })), Effect5.flatMap((validatedWebhook) => httpClient.request({
|
|
844
|
-
method: "POST",
|
|
845
|
-
url: webhookUrl,
|
|
846
|
-
body: validatedWebhook
|
|
847
|
-
}).pipe(Effect5.retry(retrySchedule.pipe(Schedule2.whileInput((error) => {
|
|
848
|
-
if (error instanceof NetworkError)
|
|
849
|
-
return true;
|
|
850
|
-
if (error instanceof RateLimitError)
|
|
851
|
-
return true;
|
|
852
|
-
if (error instanceof HttpError) {
|
|
853
|
-
const status = error.response?.status;
|
|
854
|
-
return typeof status === "number" && status >= 500;
|
|
855
|
-
}
|
|
856
|
-
return false;
|
|
857
|
-
}))))), Effect5.map((response) => response.status === 204 && response.text === ""));
|
|
858
|
-
const modifyWebhook = (params) => pipe3(Schema8.decodeUnknown(WebhookParameter)(params), Effect5.mapError((e) => ValidationError.fromParseError(e, { field: "params", value: params })), Effect5.flatMap((validatedParams) => httpClient.request({
|
|
859
|
-
method: "PATCH",
|
|
860
|
-
url: webhookUrl,
|
|
861
|
-
body: validatedParams
|
|
862
|
-
})), Effect5.flatMap((response) => Schema8.decodeUnknown(WebhookResponse)(response.body).pipe(Effect5.mapError(() => new WebhookError({
|
|
863
|
-
message: "Invalid webhook response",
|
|
864
|
-
cause: response.body
|
|
865
|
-
})))));
|
|
866
|
-
const getWebhook = () => pipe3(httpClient.request({
|
|
867
|
-
method: "GET",
|
|
868
|
-
url: webhookUrl
|
|
869
|
-
}), Effect5.flatMap((response) => Schema8.decodeUnknown(WebhookResponse)(response.body).pipe(Effect5.mapError(() => new WebhookError({
|
|
870
|
-
message: "Invalid webhook response",
|
|
871
|
-
cause: response.body
|
|
872
|
-
})))));
|
|
873
|
-
const validateWebhook = () => pipe3(httpClient.request({
|
|
874
|
-
method: "GET",
|
|
875
|
-
url: webhookUrl
|
|
876
|
-
}), Effect5.as(true), Effect5.catchAll(() => Effect5.succeed(false)));
|
|
877
|
-
const deleteWebhook = () => pipe3(httpClient.request({
|
|
878
|
-
method: "DELETE",
|
|
879
|
-
url: webhookUrl
|
|
880
|
-
}), Effect5.map((response) => response.status === 204));
|
|
881
|
-
return {
|
|
882
|
-
sendWebhook,
|
|
883
|
-
modifyWebhook,
|
|
884
|
-
getWebhook,
|
|
885
|
-
deleteWebhook,
|
|
886
|
-
validateWebhook
|
|
887
|
-
};
|
|
888
|
-
});
|
|
889
|
-
var WebhookServiceLive = Layer3.effect(WebhookService, makeWebhookService);
|
|
890
|
-
var sendWebhook = (webhook) => Effect5.flatMap(WebhookService, (service) => service.sendWebhook(webhook));
|
|
891
|
-
var modifyWebhook = (params) => Effect5.flatMap(WebhookService, (service) => service.modifyWebhook(params));
|
|
892
|
-
var getWebhook = () => Effect5.flatMap(WebhookService, (service) => service.getWebhook());
|
|
893
|
-
var deleteWebhook = () => Effect5.flatMap(WebhookService, (service) => service.deleteWebhook());
|
|
894
|
-
var validateWebhook = () => Effect5.flatMap(WebhookService, (service) => service.validateWebhook());
|
|
1118
|
+
var build2 = (self) => pipe3(self, Effect5.flatMap(buildImpl2));
|
|
895
1119
|
export {
|
|
1120
|
+
webhookErrorToLogObject,
|
|
896
1121
|
validateWebhook,
|
|
1122
|
+
sendWebhookRaw,
|
|
897
1123
|
sendWebhook,
|
|
898
1124
|
positiveInt,
|
|
899
1125
|
parseWebhookUrl,
|
|
@@ -902,11 +1128,14 @@ export {
|
|
|
902
1128
|
modifyWebhook,
|
|
903
1129
|
maxLength,
|
|
904
1130
|
makeWebhookService,
|
|
1131
|
+
makeTestHttpClient,
|
|
905
1132
|
makeIssue,
|
|
906
1133
|
makeHttpClientLayer,
|
|
1134
|
+
makeDefaultLayer,
|
|
907
1135
|
makeConfigLayer,
|
|
908
1136
|
makeConfig,
|
|
909
1137
|
getWebhook,
|
|
1138
|
+
formatWebhookError,
|
|
910
1139
|
deleteWebhook,
|
|
911
1140
|
defaultRetryConfig,
|
|
912
1141
|
createRetrySchedule,
|
|
@@ -948,5 +1177,5 @@ export {
|
|
|
948
1177
|
Attachment
|
|
949
1178
|
};
|
|
950
1179
|
|
|
951
|
-
//# debugId=
|
|
1180
|
+
//# debugId=484262147C37081864756E2164756E21
|
|
952
1181
|
//# sourceMappingURL=index.js.map
|