kira-arts 1.0.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/dist/index.cjs ADDED
@@ -0,0 +1,3050 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // Src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ KiraError: () => KiraError,
34
+ KiraErrorCode: () => KiraErrorCode,
35
+ THEMES: () => THEMES,
36
+ achievementImage: () => achievementImage,
37
+ clearCache: () => clearCache,
38
+ computeCompatibility: () => computeCompatibility,
39
+ decimalToHex: () => decimalToHex,
40
+ drawCoverImage: () => drawCoverImage,
41
+ drawGradientBorder: () => drawGradientBorder,
42
+ encodeCanvas: () => encodeCanvas,
43
+ extensionForFormat: () => extensionForFormat,
44
+ getCacheSize: () => getCacheSize,
45
+ getThemePalette: () => getThemePalette,
46
+ hexToRgb: () => hexToRgb,
47
+ hexToRgba: () => hexToRgba,
48
+ isNumber: () => isNumber,
49
+ isString: () => isString,
50
+ leaderboardImage: () => leaderboardImage,
51
+ leaveImage: () => leaveImage,
52
+ levelUpImage: () => levelUpImage,
53
+ loadImageSafe: () => loadImageSafe,
54
+ parseHex: () => parseHex,
55
+ parseImg: () => parseImg,
56
+ parsePng: () => parsePng,
57
+ pickShipMessage: () => pickShipMessage,
58
+ profileImage: () => profileImage,
59
+ setCacheOptions: () => setCacheOptions,
60
+ setClient: () => setClient,
61
+ shipImage: () => shipImage,
62
+ toAttachment: () => toAttachment,
63
+ welcomeImage: () => welcomeImage
64
+ });
65
+ module.exports = __toCommonJS(index_exports);
66
+
67
+ // Src/@Types/common.ts
68
+ var KiraErrorCode = /* @__PURE__ */ ((KiraErrorCode2) => {
69
+ KiraErrorCode2["Validation"] = "VALIDATION";
70
+ KiraErrorCode2["Fetch"] = "FETCH";
71
+ KiraErrorCode2["AssetLoad"] = "ASSET_LOAD";
72
+ KiraErrorCode2["Render"] = "RENDER";
73
+ KiraErrorCode2["Config"] = "CONFIG";
74
+ return KiraErrorCode2;
75
+ })(KiraErrorCode || {});
76
+
77
+ // Src/Utils/error.utils.ts
78
+ var KiraError = class extends Error {
79
+ code;
80
+ constructor(message, code = "VALIDATION" /* Validation */) {
81
+ super(message);
82
+ this.name = "KiraError";
83
+ this.code = code;
84
+ }
85
+ };
86
+
87
+ // Src/Utils/fetch.utils.ts
88
+ var import_canvas2 = require("@napi-rs/canvas");
89
+
90
+ // Src/Utils/badges.utils.ts
91
+ var ICON_BASE = "https://raw.githubusercontent.com/kenndeclouv/badges-discord/main/assets";
92
+ var BOOST_BADGE = {
93
+ name: "Server Booster",
94
+ icon: `${ICON_BASE}/boosts/discordboost1.svg`
95
+ };
96
+ async function getGuildMemberInfo(client, guildId, userId) {
97
+ try {
98
+ const guild = client.guilds.cache.get(guildId) ?? await client.guilds.fetch(guildId);
99
+ const member = await guild.members.fetch(userId);
100
+ const displayColor = member.displayHexColor;
101
+ return {
102
+ boostBadge: member.premiumSince ? BOOST_BADGE : null,
103
+ roleColor: displayColor && displayColor !== "#000000" ? displayColor : null
104
+ };
105
+ } catch {
106
+ return { boostBadge: null, roleColor: null };
107
+ }
108
+ }
109
+ var FLAG_BADGES = {
110
+ Staff: { name: "Discord Staff", icon: `${ICON_BASE}/discordstaff.svg` },
111
+ Partner: { name: "Partnered Server Owner", icon: `${ICON_BASE}/discordpartner.svg` },
112
+ CertifiedModerator: { name: "Moderator Programs Alumni", icon: `${ICON_BASE}/discordmod.svg` },
113
+ Hypesquad: { name: "HypeSquad Events", icon: `${ICON_BASE}/hypesquadevents.svg` },
114
+ BugHunterLevel2: { name: "Discord Bug Hunter", icon: `${ICON_BASE}/discordbughunter2.svg` },
115
+ BugHunterLevel1: { name: "Discord Bug Hunter", icon: `${ICON_BASE}/discordbughunter1.svg` },
116
+ HypeSquadOnlineHouse1: { name: "HypeSquad Bravery", icon: `${ICON_BASE}/hypesquadbravery.svg` },
117
+ HypeSquadOnlineHouse2: {
118
+ name: "HypeSquad Brilliance",
119
+ icon: `${ICON_BASE}/hypesquadbrilliance.svg`
120
+ },
121
+ HypeSquadOnlineHouse3: { name: "HypeSquad Balance", icon: `${ICON_BASE}/hypesquadbalance.svg` },
122
+ VerifiedDeveloper: {
123
+ name: "Early Verified Bot Developer",
124
+ icon: `${ICON_BASE}/discordbotdev.svg`
125
+ },
126
+ ActiveDeveloper: { name: "Active Developer", icon: `${ICON_BASE}/activedeveloper.svg` },
127
+ VerifiedBot: { name: "Verified Bot", icon: `${ICON_BASE}/verifiedbot.svg` },
128
+ PremiumEarlySupporter: {
129
+ name: "Early Supporter",
130
+ icon: `${ICON_BASE}/discordearlysupporter.svg`
131
+ }
132
+ };
133
+ var DISPLAY_ORDER = [
134
+ "Staff",
135
+ "Partner",
136
+ "CertifiedModerator",
137
+ "Hypesquad",
138
+ "BugHunterLevel2",
139
+ "BugHunterLevel1",
140
+ "HypeSquadOnlineHouse1",
141
+ "HypeSquadOnlineHouse2",
142
+ "HypeSquadOnlineHouse3",
143
+ "VerifiedDeveloper",
144
+ "ActiveDeveloper",
145
+ "VerifiedBot",
146
+ "PremiumEarlySupporter"
147
+ ];
148
+ function getBadgesFromFlags(flags) {
149
+ if (!flags) return [];
150
+ const active = new Set(flags.toArray());
151
+ return DISPLAY_ORDER.filter((flag) => active.has(flag)).map((flag) => FLAG_BADGES[flag]).filter((badge) => Boolean(badge));
152
+ }
153
+
154
+ // Src/client.ts
155
+ var registeredClient = null;
156
+ function setClient(client) {
157
+ if (!client || typeof client.users?.fetch !== "function") {
158
+ throw new KiraError(
159
+ "setClient() expects a valid discord.js Client instance",
160
+ "CONFIG" /* Config */
161
+ );
162
+ }
163
+ registeredClient = client;
164
+ }
165
+ function getClient() {
166
+ if (!registeredClient) {
167
+ throw new KiraError(
168
+ "No discord.js Client registered. Call setClient(client) once at startup before using kira-arts, e.g. setClient(client) right after client.login().",
169
+ "CONFIG" /* Config */
170
+ );
171
+ }
172
+ return registeredClient;
173
+ }
174
+
175
+ // Src/Utils/cache.utils.ts
176
+ var DEFAULT_TTL = 12 * 60 * 60 * 1e3;
177
+ var cacheEnabled = true;
178
+ var cacheTtl = DEFAULT_TTL;
179
+ var store = /* @__PURE__ */ new Map();
180
+ function setCacheOptions(options) {
181
+ if (typeof options.enabled === "boolean") cacheEnabled = options.enabled;
182
+ if (typeof options.ttl === "number" && options.ttl > 0) cacheTtl = options.ttl;
183
+ }
184
+ function buildCacheKey(userId, guildId) {
185
+ return guildId ? `${userId}:${guildId}` : userId;
186
+ }
187
+ function getCached(key) {
188
+ if (!cacheEnabled) return null;
189
+ const entry = store.get(key);
190
+ if (!entry) return null;
191
+ if (Date.now() > entry.expiresAt) {
192
+ store.delete(key);
193
+ return null;
194
+ }
195
+ return entry.data;
196
+ }
197
+ function setCached(key, data) {
198
+ if (!cacheEnabled) return;
199
+ store.set(key, { data, expiresAt: Date.now() + cacheTtl });
200
+ }
201
+ function clearCache(userId, guildId) {
202
+ if (userId) {
203
+ store.delete(buildCacheKey(userId, guildId));
204
+ return;
205
+ }
206
+ store.clear();
207
+ }
208
+ function getCacheSize() {
209
+ return store.size;
210
+ }
211
+
212
+ // Src/Utils/validations.utils.ts
213
+ function parseImg(imgString) {
214
+ if (!imgString || typeof imgString !== "string") {
215
+ throw new KiraError(
216
+ `Invalid custom badge ('${imgString || void 0}') must be an image file 'png | jpg | jpeg | gif'`
217
+ );
218
+ }
219
+ const URL = imgString.split(".");
220
+ const imgType = URL[URL.length - 1];
221
+ const imgCheck = /(jpg|jpeg|png|gif)/gi.test(imgType);
222
+ if (!imgCheck)
223
+ throw new KiraError(
224
+ `Invalid customBackground ('${imgString || void 0}') must be an image file 'png | jpg | jpeg | gif'`
225
+ );
226
+ return imgString;
227
+ }
228
+ function parsePng(imgString) {
229
+ if (!imgString || typeof imgString !== "string") {
230
+ throw new KiraError(`Invalid custom badge ('${imgString || void 0}') must be a png file`);
231
+ }
232
+ const URL = imgString.split(".");
233
+ const imgType = URL[URL.length - 1];
234
+ const imgCheck = /(png)/gi.test(imgType);
235
+ if (!imgCheck)
236
+ throw new KiraError(`Invalid custom badge ('${imgString || void 0}') must be a png file`);
237
+ return imgString;
238
+ }
239
+ function decimalToHex(decimal) {
240
+ if (!Number.isFinite(decimal) || decimal < 0 || decimal > 16777215) {
241
+ throw new KiraError(`Invalid decimal color code (${decimal}), must be between 0 and 16777215`);
242
+ }
243
+ return "#" + Math.round(decimal).toString(16).padStart(6, "0");
244
+ }
245
+ function parseHex(input) {
246
+ const hexRegex = new RegExp(/^(#)?([A-Fa-f0-9]{3}|[A-Fa-f0-9]{6})$/);
247
+ if (typeof input === "number") return decimalToHex(input);
248
+ let hexString = String(input ?? "").trim();
249
+ if (hexRegex.test(hexString)) {
250
+ if (!hexString.startsWith("#")) hexString = "#" + hexString;
251
+ return hexString;
252
+ }
253
+ if (/^\d+$/.test(hexString)) return decimalToHex(Number(hexString));
254
+ throw new KiraError(`Invalid Hex Code ('${input === "" ? void 0 : input}')`);
255
+ }
256
+ function isString(param, type) {
257
+ if (typeof param !== "string")
258
+ throw new KiraError(`Invalid ${type} (${param}), must be a string`);
259
+ return param;
260
+ }
261
+ function isNumber(param, type) {
262
+ if (typeof param !== "number" || isNaN(param))
263
+ throw new KiraError(`Invalid ${type} (${param}), must be a number`);
264
+ return param;
265
+ }
266
+
267
+ // Src/Utils/canvasShared.utils.ts
268
+ var import_canvas = require("@napi-rs/canvas");
269
+ function resolveCardColors(sources) {
270
+ if (sources.removeBorder) return [];
271
+ if (typeof sources.custom !== "undefined") {
272
+ const list = Array.isArray(sources.custom) ? sources.custom : [sources.custom];
273
+ return list.map((color) => parseHex(color));
274
+ }
275
+ if (sources.useNitroTheme && sources.nitroColors && sources.nitroColors.length > 0) {
276
+ return sources.nitroColors.map((color) => parseHex(color));
277
+ }
278
+ if (sources.useRoleColor && sources.roleColor) {
279
+ return [parseHex(sources.roleColor)];
280
+ }
281
+ return (sources.fallback ?? []).map(
282
+ (color) => typeof color === "string" ? color : parseHex(color)
283
+ );
284
+ }
285
+ async function loadImageSafe(url, attempts = 3, timeoutMs = 8e3) {
286
+ if (!url) return void 0;
287
+ const isRemote = /^https?:\/\//i.test(url);
288
+ if (!isRemote) {
289
+ return (0, import_canvas.loadImage)(url).catch((error) => {
290
+ const message = error instanceof Error ? error.message : String(error);
291
+ console.warn("[arts] failed to load local image:", url, message);
292
+ return void 0;
293
+ });
294
+ }
295
+ for (let attempt = 1; attempt <= attempts; attempt++) {
296
+ const controller = new AbortController();
297
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
298
+ try {
299
+ const response = await fetch(url, {
300
+ signal: controller.signal,
301
+ headers: { "User-Agent": "Mozilla/5.0 (compatible; kira-arts/1.0)" }
302
+ });
303
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
304
+ const arrayBuffer = await response.arrayBuffer();
305
+ return await (0, import_canvas.loadImage)(Buffer.from(arrayBuffer));
306
+ } catch (error) {
307
+ const message = error instanceof Error ? error.message : String(error);
308
+ if (attempt === attempts) {
309
+ console.warn("[arts] failed to load image after retries:", url, message);
310
+ return void 0;
311
+ }
312
+ await new Promise((resolve) => setTimeout(resolve, 250 * attempt));
313
+ } finally {
314
+ clearTimeout(timer);
315
+ }
316
+ }
317
+ return void 0;
318
+ }
319
+ function hexToRgb(hex) {
320
+ const normalized = parseHex(hex).replace("#", "");
321
+ const full = normalized.length === 3 ? normalized.split("").map((c) => c + c).join("") : normalized;
322
+ return {
323
+ r: parseInt(full.slice(0, 2), 16),
324
+ g: parseInt(full.slice(2, 4), 16),
325
+ b: parseInt(full.slice(4, 6), 16)
326
+ };
327
+ }
328
+ function hexToRgba(hex, alpha) {
329
+ const { r, g, b } = hexToRgb(hex);
330
+ return `rgba(${r}, ${g}, ${b}, ${alpha})`;
331
+ }
332
+ function drawGradientBorder(ctx, width, height, colors, cornerRadius, thickness = 5) {
333
+ const grd = ctx.createLinearGradient(0, 0, width, height);
334
+ for (let i = 0; i < colors.length; i++) {
335
+ const stop = colors.length === 1 ? 0 : i / (colors.length - 1);
336
+ grd.addColorStop(stop, parseHex(colors[i]));
337
+ }
338
+ ctx.save();
339
+ ctx.lineWidth = thickness;
340
+ ctx.strokeStyle = grd;
341
+ ctx.beginPath();
342
+ ctx.roundRect(thickness / 2, thickness / 2, width - thickness, height - thickness, [
343
+ Math.max(0, cornerRadius - thickness / 2)
344
+ ]);
345
+ ctx.stroke();
346
+ ctx.restore();
347
+ }
348
+ function drawCoverImage(ctx, image, x, y, w, h) {
349
+ const scale = Math.max(w / image.width, h / image.height);
350
+ const drawW = image.width * scale;
351
+ const drawH = image.height * scale;
352
+ const dx = x + (w - drawW) / 2;
353
+ const dy = y + (h - drawH) / 2;
354
+ ctx.save();
355
+ ctx.beginPath();
356
+ ctx.rect(x, y, w, h);
357
+ ctx.clip();
358
+ ctx.drawImage(image, dx, dy, drawW, drawH);
359
+ ctx.restore();
360
+ }
361
+
362
+ // Src/Utils/fetch.utils.ts
363
+ var NAMEPLATE_CDN_BASE = "https://cdn.discordapp.com/assets/collectibles";
364
+ var MATH_SCRIPT_FALLBACK_MAP = {
365
+ "\u{1D49C}": "A",
366
+ \u212C: "B",
367
+ "\u{1D49E}": "C",
368
+ "\u{1D49F}": "D",
369
+ \u2130: "E",
370
+ \u2131: "F",
371
+ "\u{1D4A2}": "G",
372
+ \u210B: "H",
373
+ \u2110: "I",
374
+ "\u{1D4A5}": "J",
375
+ "\u{1D4A6}": "K",
376
+ \u2112: "L",
377
+ \u2133: "M",
378
+ "\u{1D4A9}": "N",
379
+ "\u{1D4AA}": "O",
380
+ "\u{1D4AB}": "P",
381
+ "\u{1D4AC}": "Q",
382
+ \u211B: "R",
383
+ "\u{1D4AE}": "S",
384
+ "\u{1D4AF}": "T",
385
+ "\u{1D4B0}": "U",
386
+ "\u{1D4B1}": "V",
387
+ "\u{1D4B2}": "W",
388
+ "\u{1D4B3}": "X",
389
+ "\u{1D4B4}": "Y",
390
+ "\u{1D4B5}": "Z",
391
+ "\u{1D4B6}": "a",
392
+ "\u{1D4B7}": "b",
393
+ "\u{1D4B8}": "c",
394
+ "\u{1D4B9}": "d",
395
+ \u212F: "e",
396
+ "\u{1D4BB}": "f",
397
+ \u210A: "g",
398
+ "\u{1D4BD}": "h",
399
+ "\u{1D4BE}": "i",
400
+ "\u{1D4BF}": "j",
401
+ "\u{1D4C0}": "k",
402
+ "\u{1D4C1}": "l",
403
+ "\u{1D4C2}": "m",
404
+ "\u{1D4C3}": "n",
405
+ "\u{1D45C}": "o",
406
+ "\u{1D4C5}": "p",
407
+ "\u{1D4C6}": "q",
408
+ "\u{1D4C7}": "r",
409
+ "\u{1D4C8}": "s",
410
+ "\u{1D4C9}": "t",
411
+ "\u{1D4CA}": "u",
412
+ "\u{1D4CB}": "v",
413
+ "\u{1D4CC}": "w",
414
+ "\u{1D4CD}": "x",
415
+ "\u{1D4CE}": "y",
416
+ "\u{1D4CF}": "z"
417
+ };
418
+ function applyMathScriptFallback(value) {
419
+ let result = "";
420
+ for (const char of value) {
421
+ result += MATH_SCRIPT_FALLBACK_MAP[char] ?? char;
422
+ }
423
+ return result;
424
+ }
425
+ function normalizeDisplayText(value) {
426
+ if (typeof value !== "string") return value;
427
+ try {
428
+ const normalized = value.normalize("NFKC");
429
+ if (normalized !== value) return normalized;
430
+ return applyMathScriptFallback(normalized);
431
+ } catch {
432
+ return value;
433
+ }
434
+ }
435
+ async function computeBannerAverageColor(bannerUrl) {
436
+ if (!bannerUrl) return null;
437
+ const image = await loadImageSafe(bannerUrl, 1, 4e3);
438
+ if (!image) return null;
439
+ try {
440
+ const canvas = (0, import_canvas2.createCanvas)(1, 1);
441
+ const ctx = canvas.getContext("2d");
442
+ ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, 1, 1);
443
+ const { data } = ctx.getImageData(0, 0, 1, 1);
444
+ return "#" + [data[0], data[1], data[2]].map((channel) => channel.toString(16).padStart(2, "0")).join("");
445
+ } catch {
446
+ return null;
447
+ }
448
+ }
449
+ async function fetchNitroThemeColors(client, userId, fallbackAccent) {
450
+ try {
451
+ const profile = await client.rest.get(
452
+ `/users/${userId}/profile?with_mutual_guilds=false&with_mutual_friends=false&with_mutual_friends_count=false`
453
+ );
454
+ const themeColors = profile.user_profile_customization?.theme_colors ?? profile.theme_colors;
455
+ if (Array.isArray(themeColors) && themeColors.length >= 2) {
456
+ return [decimalToHex(themeColors[0]), decimalToHex(themeColors[1])];
457
+ }
458
+ if (Array.isArray(themeColors) && themeColors.length === 1) {
459
+ return [decimalToHex(themeColors[0])];
460
+ }
461
+ } catch (error) {
462
+ if (process.env.KIRA_DEBUG) {
463
+ const details = typeof error === "object" && error !== null && "rawError" in error ? error.rawError : error instanceof Error ? error.message : error;
464
+ console.warn(`[kira-arts] Nitro theme fetch failed for ${userId}:`, details);
465
+ }
466
+ }
467
+ return fallbackAccent ? [fallbackAccent] : null;
468
+ }
469
+ async function fetchUserData(userId, guildId, bypassCache = false) {
470
+ const cacheKey = buildCacheKey(userId, guildId);
471
+ if (!bypassCache) {
472
+ const cached = getCached(cacheKey);
473
+ if (cached) return cached;
474
+ }
475
+ const client = getClient();
476
+ try {
477
+ const user = await client.users.fetch(userId, { force: true });
478
+ const nameplateData = user.collectibles?.nameplate ?? null;
479
+ const primaryGuild = user.primaryGuild;
480
+ const hasServerTag = Boolean(primaryGuild?.identityEnabled && primaryGuild?.tag);
481
+ const badges = getBadgesFromFlags(user.flags);
482
+ let roleColor = null;
483
+ if (guildId) {
484
+ const memberInfo = await getGuildMemberInfo(client, guildId, userId);
485
+ if (memberInfo.boostBadge) badges.push(memberInfo.boostBadge);
486
+ roleColor = memberInfo.roleColor;
487
+ }
488
+ const bannerUrl = user.bannerURL({ size: 128 }) ?? null;
489
+ const accentFallback = user.hexAccentColor ?? await computeBannerAverageColor(bannerUrl);
490
+ const profileColors = await fetchNitroThemeColors(client, userId, accentFallback);
491
+ const result = {
492
+ basicInfo: {
493
+ id: user.id,
494
+ username: normalizeDisplayText(user.username),
495
+ globalName: normalizeDisplayText(user.globalName),
496
+ discriminator: user.discriminator === "0" ? null : user.discriminator,
497
+ bot: user.bot,
498
+ verified: user.flags?.has("VerifiedBot") ?? false,
499
+ createdTimestamp: user.createdTimestamp
500
+ },
501
+ assets: {
502
+ avatarURL: user.avatarURL({ size: 512, extension: "png", forceStatic: true }),
503
+ defaultAvatarURL: user.defaultAvatarURL,
504
+ bannerURL: user.bannerURL({ size: 512 }) ?? null,
505
+ badges
506
+ },
507
+ decoration: {
508
+ avatarFrame: user.avatarDecorationURL({ size: 256 }) ?? null,
509
+ profileColors,
510
+ roleColor,
511
+ nameplate: nameplateData ? {
512
+ imageURL: `${NAMEPLATE_CDN_BASE}/${nameplateData.asset}static.png`,
513
+ palette: nameplateData.palette
514
+ } : null,
515
+ serverTag: hasServerTag ? {
516
+ text: normalizeDisplayText(primaryGuild.tag),
517
+ badgeURL: user.guildTagBadgeURL({ size: 64 })
518
+ } : null
519
+ }
520
+ };
521
+ setCached(cacheKey, result);
522
+ return result;
523
+ } catch (error) {
524
+ if (error instanceof KiraError) throw error;
525
+ const message = error instanceof Error ? error.message : void 0;
526
+ throw new KiraError(message || "Could not fetch user data", "FETCH" /* Fetch */);
527
+ }
528
+ }
529
+
530
+ // Src/Utils/profileImage.output.utils.ts
531
+ var import_canvas9 = require("@napi-rs/canvas");
532
+
533
+ // Src/Utils/ProfileImage/badges.ts
534
+ var import_canvas4 = require("@napi-rs/canvas");
535
+
536
+ // Src/Utils/fonts.utils.ts
537
+ var import_canvas3 = require("@napi-rs/canvas");
538
+ var import_path = __toESM(require("path"), 1);
539
+ var initialized = false;
540
+ function ensureFontsRegistered() {
541
+ if (initialized) return;
542
+ initialized = true;
543
+ const fontsDir = import_path.default.join(__dirname, "..", "..", "Public", "fonts");
544
+ import_canvas3.GlobalFonts.registerFromPath(`${fontsDir}/HelveticaBold.ttf`, "Helvetica Bold");
545
+ import_canvas3.GlobalFonts.registerFromPath(`${fontsDir}/Helvetica.ttf`, "Helvetica");
546
+ const fallbackFonts = [
547
+ ["MPLUSRounded1c-Bold.ttf", "MPLUS Rounded"],
548
+ ["NotoSans-Bold.ttf", "Noto Sans"],
549
+ ["NotoSansSymbols-Regular.ttf", "Noto Sans Symbols"],
550
+ ["NotoSansSC-Regular.ttf", "Noto Sans SC"],
551
+ ["NotoSansJP-Regular.ttf", "Noto Sans JP"],
552
+ ["NotoColorEmoji-Regular.ttf", "Noto Color Emoji"],
553
+ ["NotoSansSymbols2-Regular.ttf", "Noto Sans Symbols 2"]
554
+ ];
555
+ for (const [file, family] of fallbackFonts) {
556
+ try {
557
+ import_canvas3.GlobalFonts.registerFromPath(`${fontsDir}/${file}`, family);
558
+ } catch {
559
+ }
560
+ }
561
+ import_canvas3.GlobalFonts.loadSystemFonts();
562
+ }
563
+ var FALLBACK_FAMILY_STACK = '"Noto Sans JP", "Noto Sans SC", "Noto Sans", "Noto Sans Symbols", "Noto Sans Symbols 2", "MPLUS Rounded", "Noto Color Emoji"';
564
+ function withFallback(fontDeclaration) {
565
+ return `${fontDeclaration}, ${FALLBACK_FAMILY_STACK}`;
566
+ }
567
+
568
+ // Src/Utils/strings.utils.ts
569
+ function parseUsername(username, ctx, font, size, maxLength) {
570
+ username = username && username.replace(/\s/g, "") ? username : "?????";
571
+ const usernameChars = username.split("");
572
+ let finalUsername = "";
573
+ let newSize = +size;
574
+ let textLength = 0;
575
+ let finalized = false;
576
+ while (!finalized) {
577
+ const currentUsername = usernameChars.join("");
578
+ ctx.font = withFallback(`${newSize}px ${font}`);
579
+ ctx.textAlign = "left";
580
+ ctx.fillStyle = "#FFFFFF";
581
+ const actualLength = ctx.measureText(currentUsername).width;
582
+ if (actualLength >= maxLength) {
583
+ if (newSize > 60) newSize -= 1;
584
+ else usernameChars.pop();
585
+ }
586
+ if (actualLength <= maxLength) {
587
+ finalUsername = currentUsername;
588
+ textLength = actualLength;
589
+ finalized = true;
590
+ }
591
+ }
592
+ return {
593
+ username: finalUsername,
594
+ newSize,
595
+ textLength
596
+ };
597
+ }
598
+ function getFirstDigitsAsDecimal(numString) {
599
+ const digits = (numString.length - 1) % 3 + 1;
600
+ if (numString.length < 4) {
601
+ return numString;
602
+ }
603
+ const decimal = numString.slice(digits, digits + 1);
604
+ return `${numString.slice(0, digits)}${decimal == "0" || decimal == "00" || digits == 3 ? "" : `.${decimal.replace(/0$/g, "")}`}`;
605
+ }
606
+ function abbreviateNumber(number) {
607
+ const numString = `${number}`;
608
+ const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
609
+ const abbreviations = ["", "K", "M", "B", "T"].concat(
610
+ new Array(letters.length).fill("AA").map((_, i) => letters[i].repeat(2))
611
+ );
612
+ const selectedAbbr = abbreviations[Math.floor((numString.length - 1) / 3)] ?? "??";
613
+ return `${getFirstDigitsAsDecimal(numString)}${selectedAbbr}`;
614
+ }
615
+ function getDateOrString(dateInput, createdTimestamp, localDateType = "en") {
616
+ const dateOptions = {
617
+ month: "short",
618
+ day: "numeric",
619
+ year: "numeric"
620
+ };
621
+ const iso8601Regex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z$/;
622
+ if (typeof dateInput === "string") {
623
+ if (iso8601Regex.test(dateInput)) {
624
+ const dateInstance = new Date(dateInput);
625
+ return dateInstance.toLocaleDateString(localDateType, dateOptions);
626
+ } else {
627
+ return dateInput;
628
+ }
629
+ } else if (dateInput instanceof Date) {
630
+ return dateInput.toLocaleDateString(localDateType, dateOptions);
631
+ } else {
632
+ return (/* @__PURE__ */ new Date(+createdTimestamp)).toLocaleDateString(localDateType, dateOptions);
633
+ }
634
+ }
635
+ function truncateText(text, limit = 25, fromEnd = false) {
636
+ if (text.length > limit) {
637
+ if (fromEnd) {
638
+ return "..." + text.slice(-limit);
639
+ } else {
640
+ return text.slice(0, limit) + "...";
641
+ }
642
+ } else {
643
+ return text;
644
+ }
645
+ }
646
+
647
+ // Public/ProfileImage.files.json
648
+ var ProfileImage_files_default = {
649
+ otherImgs: {
650
+ botAI: "iVBORw0KGgoAAAANSUhEUgAAAEwAAAAkCAYAAAAjMNwcAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAydpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDkuMS1jMDAxIDc5LjE0NjI4OTk3NzcsIDIwMjMvMDYvMjUtMjM6NTc6MTQgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCAyNS4wIChXaW5kb3dzKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo5NjkwMEI1RjZBMjgxMUVFOTgwREFERDFFQTZENzRCMyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo5NjkwMEI2MDZBMjgxMUVFOTgwREFERDFFQTZENzRCMyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjk2OTAwQjVENkEyODExRUU5ODBEQUREMUVBNkQ3NEIzIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjk2OTAwQjVFNkEyODExRUU5ODBEQUREMUVBNkQ3NEIzIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+tQOfMQAABBxJREFUeNrsmntIU1Ecx7+bpvmYTZfmylR0aq3oLT2tqMwekLEgqeiJ1R+9IQvqj/qjIKmIKP9IjCIyqEBb9M76o+xBYpFEr7HUskzLWs1yarbOuW7Xe7drrnZ1s+5XfnDOuQ8Pn3t+j3N3ZSjdDo56E1tHLJ1YArFA/J/6TsxATE/sELGP9gMyDjAK6TgxJSRxZSK2zAYPcttgBrECCZaglDY2c+zAVMSOcOBJchZlc4Kyoo21xHpJTDoUZbRWbl9qklxSOgUWL3FwWQPkkjv+kQK6JNBvjJz8zxDz7ex/sD5yEg70nQadQoOJrwuBxjpR7luSsIpt36wvx9bq6789Py9qDoYGRLL9ZEOuFwILScTBvqlMM0URiybtesx4rcfNuodu3XZR2EiMUkS3BZbAPh0Co7C417hTX3SOfHrCEreQN9RD5oM0zlP+Wy1XDuL1g338kRU+ocsKsk7Rfc0y+Mv5C7jQ9Axbqy65GUSCMFWZ6DScpojrvsB2R83E6KAo3lhV0xfoKs64fe/s8HGC4wxEArP7AQuKwbaI8U7D/Y0ngZ/Nbt9+bq+BbPto7QPUtzR2CNN7gcn9YE1a6TS88u0VoKFahIcRi8TACLab+bkM10wvBGF2C2APElY4jRXXVyKvpliU++eFDmHbzMr6VoECs5EdY2ASqF4B7CoJ4gbtJsAvVPD44eh0JDvErTdNJqQYjok22VnKJLZtX1n5n0p5bsmF6jFgU1QjMD1EA01PFSzaDUx9xUvrJM2v6Z3sdF10+VnA+kOUidLaS+3XtovjriyuW2aohnoYWEgSbsTo2C4tFayaJdjZL611QOYLc9wCp8syqy4Tl6kUbaI6RTzPHenKEoJHazIK12NboyFkAkLa0ScFYwPUiPQNdjpW9NVIMtgdEWcZBJ2qzdXMLRZkq1N/C5cLtEuBlZFMJGuowV0So8YG87cW1E0d1WxtQSotIURUVuhwXp+65hb1pPaBUbhvLwI/vnko6FtqMO5lLnLrOn5qfobjJG41izrJ+Uqt25A98rZidWUhTporcCt2nuDxfbX3SIApF3eG/hG8TXNBXRn2fH4ieKo+ejabGDJJotr7odizwKhuf3pEXLQaj2LmYViguu0Vi/kVsqouij7B7DB+1qOwSr4+FTz3nnkwG+uYmozARmOtFxSuDe8x/HkO9n+4z3St5G/qq1Od4gKLVcN42bE9WI7ZkqnJwsd4V6W/+c0FbHpXBLkxHyCZS2wlh2h5tRe33hKSYxHLLXTFEv3l2wpJnn29868D+yJhcD16U2BGiYPLek6BnZc4uCw9BZYjuaVLooxyKDD6sdhqppyS1J4om6WUlT1LnqZ7VrR+PCaJL5ONjd6xrDiH1s80dxF7TLfc/zEki43BbhuTc/YDvwQYAOqbIjln7aR5AAAAAElFTkSuQmCC",
651
+ botNoVerif: "iVBORw0KGgoAAAANSUhEUgAAAD0AAAAkCAYAAAA6uzK6AAAACXBIWXMAAAsTAAALEwEAmpwYAAADtklEQVRogd2az2/TZhjHP04c2oBSCmgH1DGmDsiKRVuVlYaO0MLCD6FJEwjEjxtIoO3EYZO4ILF/YMft0Gm3jTIhMQESQgMhoGgLVFSUqkBRqRhQ9QCUX+JXEzc7OPZrp3bipIkNfKQcHL9f6/m+ft73eRJbymQy7Nz3Ahu+ArYDq4CPgYjdoHeMF8AD4BJwFDiTO6C7K4JsI1wMdAGdlYyuQkSAhuxnL3Ae+A64ZR4UyBHFgV7eT8N2dAJXgNXmL82mPwNOArO9i8kTIsAJtAwGrKZ/48MzrDMb+Fk/0E2vBjp8Ccc71pFNc930Vv9i8ZTtIEyv8zEQL1kLwvQCHwPxkoWAUadnFauOtYgSf2tY5enzjONYJRokMktyPJ/sS1dEa0MYsG1OChJrkdn/bdg4PnLsDcdPpxzH79hcxaL6oOP5/UCyN8Vfpya4NzpZNq0Tuc2JK9qWW+dqabSkubMQaw3x44GZKFFng+XSlhRt0zKrrFGR+aQu4Gqmk70pLl8VKVn/aYBE5wzC1RLhaondu6r44dCrsmvNFG36m40hwtVT19iqNpnDxyYK6h8+nrSsw2QfjNydNJZL3fwgSjTI4JBaVq2ZotPbnMrnLgqTX7aFir2UQe5m1KS4T/FStEWZrq2RaFSE6aMnJhh/oqX03DmBktajHxRlelNC3M3rg2mePs9wbUDMdHtraRtaIm7V9Q/mT8/paouKsqVJDL8xpJkduKGyNvvDbeWKEL/+/jbvNRqWyOzaIo4/mhcg1iomc3hEdVyT09GacW1aiQapmy/S98I/mulkX5p9bzLGDpqIy5ztcW4YFtUHHevu6JjKT7+8rojWjGvT5tTVU1unfyBtzHhrSyivaTuGR1Ru3k5z6mwqb2dXLq1r082m2tyoyHR32f9l1qjI1NZIjgGcPP3WVWkrt9aMq40sEZeZO8f9ntfRPv0OrZK4ik75XAwbHVPp65+avg1LZGO9xVeG8vbiflPQdG2NZGk7e/5N2RpSoioHv58JaJ2R27bUDwrmbEe7bGk79V07l8Eh1WhUADasKb1DqzQFTX/RPLUhceL2sKiRzcve3XUtZZ9wFFcn3mO6uyKSfqdf+hqJd7wGkd73fQzES/4DYbrHx0C85BwI03/4GIiX/AnC9AXgon+xeMIZsh7NJWsP8MyXcCrPI7RHtoDV9B3ga2Dc64gqzDiwGc0fMLU5uQSsQHuY/SFwHoih+TKwa5vuAGuA9cA2tNcvFlDCUxAfeIlWfvXXL/62G/Q/ynk4UBWNnikAAAAASUVORK5CYII=",
652
+ botVerif: "iVBORw0KGgoAAAANSUhEUgAAAFgAAAAkCAYAAAANdf2OAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFGUlEQVRoge2aa2wUVRiGn92dbXdLIIXKD1IF27TUMukllUqpFpTUcEmwxEuIGE1KIlEgoQmoQCRcRH6gVKJIIo0xQqMGEm6NpYnERDCyClZKaWltrUrTkCiFBkNvu7Prj2F2Znc67eytS5Y+SX/szPnOfn3POe/5zmktPp+Pl9f8h4ZUYD3wHCACKUwwFv1AG1AH7Af6lBdCUMOlwBEgbZwSSxRSgKJ7P+uB14B6AKum0XLkEZgQNzLSgNPIevoFTgW+AGzxySnhsCHrmaoIvJaJmRtt0oC1isAV8cwkgalQBM6KaxqJS7Yi8LS4ppG4TLWO3SY6rFiWNF5fdV8RXAfHhIolSaxckUxersBnXw7yz01vSPElRWqabZ0SfXd8hm3FHBuTJ1kM37saPTGJNcJy7yRnnHGE5M0R2Frl9H+WJDh0eJBzF9ym4kuKBDa8ocZ/c3yQUw3Gse9tTiErc/Rq03XRzYn6Ya73BA50JLFGxNQinA4Lb61zBjyz2WDmw+a/dt7jgYtsTk7ki66k2M6Od1IQc0Iv+0ONjalFbKlyYrcHPvul0UPtsSHTfRTkBaaYLwrMTLeamkGui25+/lVd1pmPWil/Ogmnw4LTYaFyVTKbtvdHPVZLzARe9UIy2UHL7eYtLwc+HzDdR8USO06H3hOfmifw1fHhMeP/7fUG+KarEbr+8votJ32GDTHHRku7FNVYLTGxiOxMG8sX66uGvZ8M4DZnvUCgHXx/ThX0yXn2kZqbInijKhDN20Q4sVEXOMkOuzbrbzhrjw3RbXJjAEidYiFfVAU+dnqYW7fl+GlTrWH5ZzyIusDbNunFvdYh8e13Yy9pLcvK1Vl6pcVD3x0fl5vVGVRaHJ67lZcFxjW1jL7EI40NKcstG5xMf8jKnv0D3OzVz8bVrzjIygjy3V4vez4aezMIpqhATa21XRa2uVVi0QL52fwn7NTUjr5Z5s4WWPW8+nl6mpWSYnXgOrskQw+NJFaLaYEXzLf7l2z1rkl88OkAza3qjJpbKPDsQr03flwziCfE+lzMsZE+Qx2oH36SO3A1elgz6PPv5OVlAmfPG3eelWkzrGt7bkjsO2i84UYSq8WURRSIAm9WOvyf7XbYWuVk5YpkQK5tN6516uIOHx2io8v8ElTQLn/FHhSaNDZRXBT6ZtfZJVHXMMTufQOjngijFWtqBjv12gHy/ULGLCupU/TjdKXVw5mzofmuQqGm9s0XBb4+NHnEdvmiQOoUi+EvW9cwZKqci3asFlMz2HXJw6btd2nv1M/GAlFg1iOB3UgSfHjAfL2rpbxMYFoId1ALS8flOiVsTGfXc8PLjr39vP6qg0Vloy/N96v7cYd+LwKA+JiaUs8NicYmfUe5swW/P5bNt496NxFvQh7+miODXOuQWLfaMeL7+rPDXOsI3XdBrn21R+PzF9wjiifmSLy7US4H02fYTB+d40FYdfCPLjdv77zLn9cDhbzaJnHkqPl7hmAWlgoBR2OlegimpV3yHzoAFj8T/sku1oR90Oju8bJ1d79/I/P5oNpk6WLE3EL94cKI3zX7QWHe/evDUbkPrliaxN/dXi5fDdN4E5ioDP2pM5GXM4nKuP1N7kFFEfhWXLNIXG4rAv8R1zQSl05F4JPxzCKBOakIfBDojWcmCUgvcFARuA+oBMI7gk0QjISsZ5+2iqgDXkTz39kThEUf8BKynroy7SSQAWwDLgGRHc0eHAaA34CdyPqdUF78DyvRxMINRXPNAAAAAElFTkSuQmCC",
653
+ frame: "iVBORw0KGgoAAAANSUhEUgAAA3UAAAEvCAYAAADihOiYAAABN2lDQ1BBZG9iZSBSR0IgKDE5OTgpAAAokZWPv0rDUBSHvxtFxaFWCOLgcCdRUGzVwYxJW4ogWKtDkq1JQ5ViEm6uf/oQjm4dXNx9AidHwUHxCXwDxamDQ4QMBYvf9J3fORzOAaNi152GUYbzWKt205Gu58vZF2aYAoBOmKV2q3UAECdxxBjf7wiA10277jTG+38yH6ZKAyNguxtlIYgK0L/SqQYxBMygn2oQD4CpTto1EE9AqZf7G1AKcv8ASsr1fBBfgNlzPR+MOcAMcl8BTB1da4Bakg7UWe9Uy6plWdLuJkEkjweZjs4zuR+HiUoT1dFRF8jvA2AxH2w3HblWtay99X/+PRHX82Vun0cIQCw9F1lBeKEuf1UYO5PrYsdwGQ7vYXpUZLs3cLcBC7dFtlqF8hY8Dn8AwMZP/fNTP8gAAAAJcEhZcwAACxMAAAsTAQCanBgAAAXAaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA3LjEtYzAwMCA3OS43YTdhMjM2LCAyMDIxLzA4LzEyLTAwOjI1OjIwICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIiB4bWxuczpwaG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9zaG9wLzEuMC8iIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIDIyLjUgKFdpbmRvd3MpIiB4bXA6Q3JlYXRlRGF0ZT0iMjAyMi0wNC0yOVQxOToyODowMi0wNTowMCIgeG1wOk1vZGlmeURhdGU9IjIwMjItMDQtMjlUMjA6MTk6MzEtMDU6MDAiIHhtcDpNZXRhZGF0YURhdGU9IjIwMjItMDQtMjlUMjA6MTk6MzEtMDU6MDAiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6ZTUwMDE2ZGYtZDZjNS1lYTQ5LWE4MWEtNGEzZGM5YzE4NWJjIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjY1NDcxQjFDQzgxQzExRUNCRjBEOTkzMEY5NTU3MTIwIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6NjU0NzFCMUNDODFDMTFFQ0JGMEQ5OTMwRjk1NTcxMjAiIGRjOmZvcm1hdD0iaW1hZ2UvcG5nIiBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NjU0NzFCMTlDODFDMTFFQ0JGMEQ5OTMwRjk1NTcxMjAiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NjU0NzFCMUFDODFDMTFFQ0JGMEQ5OTMwRjk1NTcxMjAiLz4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6ZTUwMDE2ZGYtZDZjNS1lYTQ5LWE4MWEtNGEzZGM5YzE4NWJjIiBzdEV2dDp3aGVuPSIyMDIyLTA0LTI5VDIwOjE5OjMxLTA1OjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgMjIuNSAoV2luZG93cykiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+c9rTwAAADM5JREFUeJzt3W3ItvVdwPHvfa10zAcmtIjYA9ltk9GuIDVkmJSZuWER5AqC6F2QwbAWIsXAiCiJae9WjKAHRNpe1cYmexO4GrIHAkWZGck9x8i5OXG3s9zm3YvDGx+aXsd5ndd158/r84GLG+X//x3/8+WX4zzO41hnxrHq4uqy6p3VRdWPVD9QnV+de4bOAQAAcJBOVk9WX6serh6q7qs+V32xOnXYBzh2iLPfUF1X/VJ1TfWmQ7wWAADAq81j1aeqf6o+Xn3rMC5yGFF3SfU71XtzBw4AAKCWO3ofrT7UchfvwBxk1P1s9YHn/gUAAOB7u7u6pfrngxh2EFH3juqD1bUHMAsAAOCouKt6f/XANkNet8Xes1vq8u+rt29zCAAAgCPoePVbLW31r9V39zNkv3fqLqz+obp0n/sBAAB43uerX6v+c9ONO/u42PXVvyXoAAAADsqlLZ11/aYbN/365R+0/FrL6ze9EAAAAK/o7Ja3CHy7+vTaTWu/fnms5cdQfnfzc73IZ6p7qkeqL1dPtLyr4eSWcwEAAP4/nNvyju43Vm+u3lJdXr1ry7m3Vb/fAb68/Lbnhu3n70R1a3V1tXtQBwIAAHiV2m3pn1urh9t/S/3pQR3o5n0e4P7qxoQcAABwdO1W72vpo/101Y3bHuBXqmc3vOhj1U2JOQAAgNN2Wzrp0Tbrq2fbx4+nnHZhyzNvm1zwjupn9ntBAACA17grW7ppk856oqXPNnJWy3sSNrnQh3N3DgAAYC+7Lf20SW99oaXTVrtlg+FPVzck6AAAANbabemop1vfXresHX58g8FPV9dt/3kAAACOpF+uvtv6/jq+ZugnVg481VKWAAAA7N8NrW+wT+417IoNhnmGDgAAYHubPmN3xSsNW3uX7s4EHQAAwEHZbemsNT32iZcbcsnKAV+vrjqczwEAAHBkXdXSW2u67Ce/14C/Xrn5pkP8EAAAAEfZTa3rsr986cZzqpMrNj6Yr10CAAAclt2W7tqrzR6vzn7hxl9dscldOgAAgMO39m7d9S/cdMeKDSdylw4AAOCw7bb0116N9jenNxyrvrpiw5+foQ8AAABw1N3e3o32pdOLL16x+FR19Rk7PgAAwNF2bes67fhOddmKgZ9puZsHAADA4ftKdc+KdVfsVD+xYuE91b1bHQkAAIC17m25ubaXd+5Ux1csfGS78wAAALChEyvWXLRTvXXFwv/a8jAAAABsZs0jcG/eqS5YsfDJLQ8DAADAZtZ02AU71XkrFp7c8jAAAABsZk2Hnbc26r615WEAAADYzJoOO2+nOmvFwme2PAwAAACbWdNhZ+0c+jEAAAA4NKIOAABgMFEHAAAwmKgDAAAYTNQBAAAMJuoAAAAGE3UAAACDiToAAIDBRB0AAMBgog4AAGAwUQcAADCYqAMAABhM1AEAAAwm6gAAAAYTdQAAAIOJOgAAgMFEHQAAwGCiDgAAYDBRBwAAMJioAwAAGEzUAQAADCbqAAAABhN1AAAAg4k6AACAwUQdAADAYKIOAABgMFEHAAAwmKgDAAAYTNQBAAAMJuoAAAAGE3UAAACDiToAAIDBRB0AAMBgog4AAGAwUQcAADCYqAMAABhM1AEAAAwm6gAAAAYTdQAAAIOJOgAAgMFEHQAAwGCiDgAAYDBRBwAAMJioAwAAGEzUAQAADCbqAAAABhN1AAAAg4k6AACAwUQdAADAYKIOAABgMFEHAAAwmKgDAAAYTNQBAAAMJuoAAAAGE3UAAACDiToAAIDBRB0AAMBgog4AAGAwUQcAADCYqAMAABhM1AEAAAwm6gAAAAYTdQAAAIOJOgAAgMFEHQAAwGCiDgAAYDBRBwAAMJioAwAAGEzUAQAADCbqAAAABhN1AAAAg4k6AACAwUQdAADAYKIOAABgMFEHAAAwmKgDAAAYTNQBAAAMJuoAAAAGE3UAAACDiToAAIDBRB0AAMBgog4AAGAwUQcAADCYqAMAABhM1AEAAAwm6gAAAAYTdQAAAIOJOgAAgMFEHQAAwGCiDgAAYDBRBwAAMJioAwAAGEzUAQAADCbqAAAABhN1AAAAg4k6AACAwUQdAADAYKIOAABgMFEHAAAwmKgDAAAYTNQBAAAMJuoAAAAGE3UAAACDiToAAIDBRB0AAMBgog4AAGAwUQcAADCYqAMAABhM1AEAAAwm6gAAAAYTdQAAAIOJOgAAgMFEHQAAwGCiDgAAYDBRBwAAMJioAwAAGEzUAQAADCbqAAAABhN1AAAAg4k6AACAwUQdAADAYKIOAABgMFEHAAAwmKgDAAAYTNQBAAAMJuoAAAAGE3UAAACDiToAAIDBRB0AAMBgog4AAGAwUQcAADCYqAMAABhM1AEAAAwm6gAAAAYTdQAAAIOJOgAAgMFEHQAAwGCiDgAAYDBRBwAAMJioAwAAGEzUAQAADCbqAAAABhN1AAAAg4k6AACAwUQdAADAYKIOAABgMFEHAAAwmKgDAAAYTNQBAAAMJuoAAAAGE3UAAACDiToAAIDBRB0AAMBgog4AAGAwUQcAADCYqAMAABhM1AEAAAwm6gAAAAYTdQAAAIOJOgAAgMFEHQAAwGCiDgAAYDBRBwAAMJioAwAAGEzUAQAADCbqAAAABhN1AAAAg4k6AACAwUQdAADAYKIOAABgMFEHAAAwmKgDAAAYTNQBAAAMJuoAAAAGE3UAAACDiToAAIDBRB0AAMBgog4AAGAwUQcAADCYqAMAABhM1AEAAAwm6gAAAAYTdQAAAIOJOgAAgMFEHQAAwGCiDgAAYDBRBwAAMJioAwAAGEzUAQAADCbqAAAABhN1AAAAg4k6AACAwUQdAADAYKIOAABgMFEHAAAwmKgDAAAYTNQBAAAMJuoAAAAGE3UAAACDiToAAIDBRB0AAMBgog4AAGAwUQcAADCYqAMAABhM1AEAAAwm6gAAAAYTdQAAAIOJOgAAgMFEHQAAwGCiDgAAYDBRBwAAMJioAwAAGEzUAQAADCbqAAAABhN1AAAAg4k6AACAwUQdAADAYKIOAABgMFEHAAAwmKgDAAAYTNQBAAAMJuoAAAAGE3UAAACDiToAAIDBRB0AAMBgog4AAGAwUQcAADCYqAMAABhM1AEAAAwm6gAAAAYTdQAAAIOJOgAAgMFEHQAAwGCiDgAAYLCd6pkV68467IMAAADwIms67Jmd6psrFr5hy8MAAACwmTUd9s21UXfulocBAABgM2ui7uRO9Y0VC8/f8jAAAABs5o0r1jy+U31pxcIf2u4sAAAAbOgHV6z58k71HysWvmXLwwAAALCZt61Y89BOde+KhZdXu9udBwAAgJV2q3etWHdf1cXVqRV/Vx/GSQEAAPg/rm1dpx3fqR6svrZi6M8fylEBAAB4qV9YseaRXvA43R3tXYAn8hVMAACAw7bb0l97NdrfVu08t+kfVwx+a3XNAR8WAACAF7umpb/28rEX/sc51cn2LsEHc7cOAADgsOy2dNdebfZ4dXY9f6fuqeojKy7wYy0P7AEAAHDwrmnprr18pPqfl/7PS1v36ypfr646mPMCAADwnKtaemtNl13yckPuWjngznwNEwAA4KDstnTWmh6765UGXbFyyKnqwwk7AACAbe229NXaFvvpvQZ+coNhNxzoRwEAADh6bmh9g73iXbrTLqqeXjnwqeo9B/ZRAAAAjpb3tHTVmv56uqXXVrll5dDTYXdDvooJAACw1m5LR60NulPVH21ygbOqL2ww3DN2AAAA62z6DN2plj47e9MLXVg9seGF7qiu3OcHAwAAeK27sqWbNumsJ6of3e8Fr6+e3fCCj1Y35a4dAADAabstnfRom/XVsy1dtpWbN7zo6b/7q/cl7gAAgKNrt6WL7m9/XXXzQR3k9n0e4FT1cHVrdXUCDwAAeO3bbemfW1t6aL8tdfuaix1beahj1W3VjSvXv5x/qT5bnai+Uv139WR1svrOlrMBAADOpO+rzq3Or15f/XD1tuqnqiu2nP0X1e+1xN0rWht1p/1h9cf72AcAAMDeTlUfqP5k7YbXbXiBT7d8F/Ta9vFzmgAAALysJ6vfqP5qk037veN2vLqzunSf+wEAAHje56tfrx7adOOmd+pOe7z6u2qnunyLOQAAAEfZd6o/q36z+up+BhzEs3HvqD7Y8pVMAAAA1rmren/1wDZDdg7gIA9U765+rrr7AOYBAAC8lt3d8sqDd7dl0NXh/IrlZdVvV+9t+XlPAACAo+5k9dHqQ9XnDnLwYb6a4JzquuoXq2uqNx3itQAAAF5tHqs+VX2s+nj11GFc5Ey9b+5YdXHLS/h+vHp7y0v5zq0ueO7f7z9DZwEAADgI3265A/eN5/49Uf17dV/12eqLrXh5+Lb+F2koYlXxK9cZAAAAAElFTkSuQmCC"
654
+ },
655
+ statusImgs: {
656
+ dnd: "iVBORw0KGgoAAAANSUhEUgAAAD4AAAA+CAYAAABzwahEAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDcuMS1jMDAwIDc5Ljk4ZDc5NDIsIDIwMjIvMDMvMjEtMTE6NDA6NTkgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCAyMi41IChXaW5kb3dzKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo3MzBGNUZCRjkyRTcxMUVEOERFOEY2OUQ5Nzg3MzEwOSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo3MzBGNUZDMDkyRTcxMUVEOERFOEY2OUQ5Nzg3MzEwOSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjczMEY1RkJEOTJFNzExRUQ4REU4RjY5RDk3ODczMTA5IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjczMEY1RkJFOTJFNzExRUQ4REU4RjY5RDk3ODczMTA5Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+ptCIzAAAAy1JREFUeNrsms9LVFEUx68hOqRT0B+QaWo/cFFYCxdBuu8HA0FWEFS0b1mGkWhRi/oHok2WaRD0A2yl7VpkJEhS9sv8AwJziJnBqO9hzlCLudP7ce679+k98N28N++e83lzf5zz7q37feCgWo+2Qa1T8+Ae3IN7cA++lqw+AR+7oV6oG9oJbYWaoc3QMpSHlqD30BtoGpo3HVSdoQSmBToLnYC2R3j+M/QAugstpgG8HboMnRTqTavQfWgY+uTiGM9AV6E56LTgEKrn9ua4/YxL4B3QK2hQMrAqL3aQ/XS4AE6T1mtoT0KTMfmZYb/WwHPQJM/OSdom9puzAd4HjUGNlpbhRvbflyQ4jbHHUIPlHKSB4+hMApze9LiF7q0ziuNhlEk1LPglaK9j2SfFc9FkAtPO62lGuWdFqCtMkhPmHx9yFLoyBIdMdPU26JjjBRfF1yoNfi6hSi5uenteGrw/JWV2vyT4LmhbSsBbuP4XAf9fdvSMf5OlVcKgsuzneYD6QQS8u8Y9qr0P81eTvOF/M89+DrFfne2TAt+huU5vfsRSlx7hnlbNOqXA2zTXb1kez7drjHMR8C2a6zOWwXX+s1LguipsxTL4So16XQS8pNJlP6TAv8fpUgatOU5PDAL+Jc6yYdD2a64vSYEvaK5fsAyu8/9BClw3e1IiMWAJeoD9R15tgoBP17hHOxxPOE1sMgzbxH6esl+dvZT8ArMYNDGwbN+CFlRBy9KxlCxlgeMMCn5HlTfwXLZfHKcoOG3bPnIcfILjFAUno027oqPQFNeVMA+EAadPtzccBb8JfTQFTnYdeusYNMVzLexDYcEL0HFVPrvigi1zPAXT4JUUNudA1VbiOBaiPBx1m3gKOmURvsT+p6I2EOdgAC1vR4LWv8L19tG4y2vcoyAvuDydTQh6lv1Nxm1I4vAPLSM9qrxpZ2qdL3L7PWGXLZPgldmeEgjaqr0nmN6ucntd3H5B6k2aOtlIFdIZnoBaIzz/FRpVKTrZWM1oL4u2fipnWam83aj+nmX9yeXkv2dZ35kOKomt33mVwKFcW2M8debBPbgH9+Ae3IOvAfsjwAD7bpEEX3YuqAAAAABJRU5ErkJggg==",
657
+ idle: "iVBORw0KGgoAAAANSUhEUgAAAD4AAAA+CAYAAABzwahEAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDcuMS1jMDAwIDc5Ljk4ZDc5NDIsIDIwMjIvMDMvMjEtMTE6NDA6NTkgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCAyMi41IChXaW5kb3dzKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo2RTVCOEFCOTkyRTcxMUVEOTM3RERBMUE4RjdBMUM4MCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo2RTVCOEFCQTkyRTcxMUVEOTM3RERBMUE4RjdBMUM4MCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjZFNUI4QUI3OTJFNzExRUQ5MzdEREExQThGN0ExQzgwIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjZFNUI4QUI4OTJFNzExRUQ5MzdEREExQThGN0ExQzgwIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+WA4qawAAAwpJREFUeNrsmj1oFEEUxyd+RsFECaaNEQ0iEfwstItFbARFEBUE0UKIgtiJjWKw0UpFr1Fs/IhGsI1aJDaawlMDmuBd/C4V1FPQyxrR/2NeETTn7ey+ud3ZzIMfhLudt/NLsjszb6bu9001JWOaUl7ci3txL+7FvbjrMSPBe28DF8EP8B68AI/BABixffO6hCcwB8H5ST5/Ba6Dy+BtFsUpboAdFb4bB9fASfAya8/4IfDlP4/iHvAMnAD1WRL/AM5UuYaEj4FBsDRLb/UcCEJctxLkQUdWxD+CeyGvbQB9PCpkYhy/a3DtbNADNmZB/Inh9bPAbdDmuvhohDaNPBzWuyxeithuFTg6VefqR8ASV8UbY7Sll123q+JxJybbQauL4qsFVpr7XRTvFMixyzXxhWCTQJ4WsNwl8QM8IZGIDlfE6a99WDDfWlfEz4H5gvnapMT3WpSm0tNO4ZwtUuIX4i4BKwTlPGsh7zwp8TmgF3QJdq6Lc063IN4gJR5wB3O8Bm6O0almzpGzJE3xVUr804Sf6XksKF3/ajLoTBO3KVh4pv+Ob2EuClNefgA2TPL5T6WrJlQyegReg8/83QKwGKzjGVmn4DhdLQYr9Pef+W21KFZINBNsZtIUBal/9bxja/O8lPiAY+L3pcRpA++dI9LUz2HJKWuPI+Kh+xlW/JLSG3hpjl/cT1Fx2ra9lXLxXu5nqDDZJqYq5nOlC3tpizGwQhnU5k2WpbQ/fSqlf+3TynBDwvRgAO1YPFS6iJ+WeMoTrLJJI9NCRJnn2qWUSJe4P2XThlEqMEVeSwcJSwfcj2KUxlFLT/1gd4LyAd+/P2qCODU3Gt62hF3/Cq+3t8YdXuMWG+8oXdUcqpH0EN+vL24iiSorDSPrld60G7M4TnfzfUYlEkqVl+mtehy0gyuC09txztfO+ctSv0lbB/wWgX38AmqN0P4NuKocP9lIe1l0SGcNWKZ03Xuu0vvhNA5/5+XkxLOsw7Y7VYtDvCOqBodyk3rGnQsv7sW9uBf34l48A/FHgAEA3wORBIONQMEAAAAASUVORK5CYII=",
658
+ invisible: "iVBORw0KGgoAAAANSUhEUgAAAD4AAAA+CAYAAABzwahEAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDcuMS1jMDAwIDc5Ljk4ZDc5NDIsIDIwMjIvMDMvMjEtMTE6NDA6NTkgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCAyMi41IChXaW5kb3dzKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo2OUE0QkE5MzkyRTcxMUVEOTRDMkI1MjkwRTA0RDVCNyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo2OUE0QkE5NDkyRTcxMUVEOTRDMkI1MjkwRTA0RDVCNyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjY5QTRCQTkxOTJFNzExRUQ5NEMyQjUyOTBFMDRENUI3IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjY5QTRCQTkyOTJFNzExRUQ5NEMyQjUyOTBFMDRENUI3Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+5VhQjAAAA+9JREFUeNrsWl1LFGEUnkpWCVOoi+jLb63Ei0ITQgv0DyRCkBFJFN11URdGgRtuUGhQfyAiCrIPqEu70iAjUCNBlPI7k6ILA2uJdVXoHPZZiljsPTNnZladAw+CM+8555l9553nPe/ZcKH1lrUebaO1Ti0gHhAPiAfEA+JryTI8iFFOqCNUEvYR8gjZhFzCPCFKmCF8ILwj9BBGVivxfMJZwklC8Qr35QK7CIcJZ/D/CcIjwj3C9GqY6iWE+4RxQut/SK9kxRg/Bn8l6Uo8i9BGGCI0K86kDPgbgv+sdCJeSnhLCGsmluLBhhGnNB2I86LVTzjg0WLMcQYQ1zfijYQuLE5eWg7iNvpBvJ7QScj06TOcifj1XhLnd+w5IeSzBgkhjzIviPOTfuLD9F5JBzy2s6hKiV8lHHSY7DLhM2ESf5cc+uN8rrhJnEVEi83k5gh3CEcgV/MgUpLy9Siuz9n0f1kqciTEIzam1CLhOqGAcInQS4j9c88C4TWuF+D+RRuvYMQN4kWE48JkvhJqIDyihmOiuL8G4yXG+RVqEz8nlKGzhFqIGzvWj9diVihvz2sTbxIkEIe4mHS4aE3AT1wwpkmT+H68e6bW4eCXTvXLdwi3w+VaxCXqiFflduVvdbtwta/TIl4pCPpAsJCZWhR+Ta1Ki/heQdAXLik0id8yLeJFhgFZgfW5RLxPoPDytYhvNQz4DWLEDVuAfxPbokXcdBf2w+UNian/HC3icc2ADgsQag/IhPh3w4DbXSxMZMK/if3UIm6qwFgyVrtEvFogmWe0iI8KEmxwibjE70ct4gOCoM3YX2taNvya2oAW8R5B0G0oCmhaC/ya2ist4nyA90mYaJUS6UPCB8l5DmtuSzsFwUOQmIUOSbNilFZzjfM0JX7XkhUFdxPeOPjleVwv/JjaMvJUJc5FgWfC5HeAfJtgwcvG/b0YL7GnyFOVOFvYhhYPYdw04baVKEdlpRAntbg+jfulQojzuiYZIKmjjaMoELYxdXlVvgjwlPxiJSqpHH+n5fxYmas0Y5IB0gOFm4T3DpPcRNiDxStPgTTnc0M6SEqca+InrETvSjrYPPKJuU08KWGl1U83LFnNHbUz2O4xcTfhlI/k44jfbdeBk8YA/rwd86AAkWq/3WDj86pGnO0lxMagR6QHEa/LqSON5h/+jHCPWsRyt+YWQZwxDYda7V4xCIgKwkPL+Zl30pbgrwL+Y1pPUrvBj0XOaSvRLsLHvVM2/UxhfCn8jWtPIbdaOpPSk8FnWXwMlexl5br3ZutPL+svbCf/7mUddnux8KKJd8TyoCnX76m+aiwgHhAPiAfEA+IB8TVgvwUYAD4Gvbi4ORocAAAAAElFTkSuQmCC",
659
+ online: "iVBORw0KGgoAAAANSUhEUgAAAD4AAAA+CAYAAABzwahEAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDcuMS1jMDAwIDc5Ljk4ZDc5NDIsIDIwMjIvMDMvMjEtMTE6NDA6NTkgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCAyMi41IChXaW5kb3dzKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo2NThGMDEwODkyRTcxMUVEQTY1MDhDRDFERjZDQUE5NCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo2NThGMDEwOTkyRTcxMUVEQTY1MDhDRDFERjZDQUE5NCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjY1OEYwMTA2OTJFNzExRURBNjUwOENEMURGNkNBQTk0IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjY1OEYwMTA3OTJFNzExRURBNjUwOENEMURGNkNBQTk0Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+tV936QAAAsVJREFUeNrsm99LVEEUx2dDVgk16A9wS12z8KGwFx/dfyBZiDKkHpL+BKMgI4Oi/oaQIFJT8NWetLce2kgQpR+m5R8QWBHrYtD3cM+SDwp77z0zd47Ogc/jzJzP5d6ZMzuzOfPyijmKccwc0QjiQTyIB/EgfpiiycEY58Ag6Ae9oAO0ghNgG/wGW+AjeA+WwJrtpHKWCpgCuAmuga4E7b+CKTAJvml41bvBc7AO7iWUNtyO2n/h/rp9FW8BD8AKuCH4CTVxfyvcf4tP4kXwFoxLJrbPgx3ncYo+iNOk9Q6cdzQZ0zgVHjcz8TJY4NnZZbTzuOUsxEtgGjRntAw38/gll+L0jc2DfMY1SJ7z6HEhTk/6VQav90FBecwkmVTjit8FFzyrPimfOzbFqYgY87T0vh23yIkjPmFxnZaY7CZsiHeCy55vuCi/09Lio452cmnL21vS4sNKttnDkuJnwSkl4gXe/4uIl4yuGJQS71cmflFK/Iwy8R4p8U5l4gUp8ZPKxNukxPPKxNulxGvKxH9Kif9QJv5LSnxDmfiWlPhnZeKfpMQrysQrUuJLysTfSInTAd53JdKU56rktnRaiXjDeTYq/gzsei79l/MUFadj2znPxWc5T1FxCjq02/FUmvK6H6dBHHE6837iqfhTE52lWxGneAw+eCZN+TyK2yiueBVcNdHdFR9im/Op2havl7BlD3ZtNc4jUUmd9Jh4EYxkKF/j8ReTdpDmYgAtb5ca3f8K77eH0i6vaa+CvDbRr5rLjqSXebyFtB1JXP6hZWTARId2ttb5He5/IO6yZVO8PttTAdEHXgiWt7vcXx/3X5V6ktIX/KjIuW6i6yIPwWbCfja5fZH7W5d+hXIO/pNCZ1l0DFW/y0q/ex83/++y/uHt5N67rKu2k3Jx9LtmHFzKzfpVVxNBPIgH8SAexIP4IYh/AgwAUZF3I1xau4QAAAAASUVORK5CYII=",
660
+ phone: "iVBORw0KGgoAAAANSUhEUgAAACkAAAA+CAYAAAC2szLVAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDcuMS1jMDAwIDc5Ljk4ZDc5NDIsIDIwMjIvMDMvMjEtMTE6NDA6NTkgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCAyMi41IChXaW5kb3dzKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo4QkI3RjFBQTkzQUUxMUVEQjYwRkNCMjA5OTlGRUI1RCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo4QkI3RjFBQjkzQUUxMUVEQjYwRkNCMjA5OTlGRUI1RCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjhCQjdGMUE4OTNBRTExRURCNjBGQ0IyMDk5OUZFQjVEIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjhCQjdGMUE5OTNBRTExRURCNjBGQ0IyMDk5OUZFQjVEIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8++UgzsQAAA8dJREFUeNrsmsuPDEEcx7/9m269s2tY70dCsgfxOtiseB4kIqw4sA4iToiLvfgDXEREXASJCyKckTghuBIn8YjEI8LKkgjWWvuanZnuKr/qHmzYx+xUdfVE/JLqzPSmf/WZ36uq91cO7qwHhnIABUBhMtDbuAkNA7shMs0AFvNwYEe64YgnCL37COVZTPtcQCkLCGKAu2sYrh4o8RDeJRSy+0ECqYpAJ+ry7ZDiFkiCINz4D/kpDyLATIDUhbAQQw03IfydKPpw0TsfkLjMl3WKGpJQE6K8GXrXUfKaiAGbEXj7IsCaE2byC+cIVGyPvtSqCKeVUKxbm3qijC2DbEk0obYlVFmSqXFIKMiw1iHdUe6f5PHB4mrzu4wDe3m0jA/pOEcg5aB1kzmRTRbz3C1/unskWVR+wDagksaRYnLsB23AjjMHmVCSJGDlkEmBVqiTklBqWhclqdyUDrIxie6zZHOyan8cWXObhvXJSnxpxjElnqkGEs3cC81IMIZKltm3ruFQBmuqm9Yqkp4lE9yZG34LlfGoWcjhcAZBKRFAw6CUGKBBUEoU0BAoJQ5oAJSsAGqCkjVAjWfJKmCVOsg6YBW6KBXACeqk1AAnoJtSBaxwjtEgX1kD/Bv0W2X7SSlP8/WT9T1ZDLqh0k3vwX97P/kf0oSIsjrhxKP2XsQYyis+Rei+gBtk+cYWBG7WRKdN35Kx1Z5DyM3I9qv28x74A23w800MfgKOTNmSCtALXoOCFSh4wS8XR01U+QmhOMwh8A6uPJ+iJR3VltwORwTsZv6s/seuuhzqjTHDP8JXPfQLDHpbx6LVWzJgiPqB+8h1vYzgcl9jwJ5ZQF0/ML2T73Uj6p8X6k+ga+5WuMIypEoIQY+iUwc/55auSp74JELPvLj5qywYum90EkgjJhVkhiIgWY5FBeSWEJ1G6M8NDyZHF9Kp2pJBZiOXmdj1CtBTbUpRtiwNq5VytU7063VpCctR8nZg5kdg6heg9FMVU2ZEDK1iknBML7sFPuuVIfcK18eVmDSk3D9CVDgX+bpMD9INn2ktYX7eR9eCh+idfZSTZmnZOw0csjtZ7z3+ekCzluccXGvbhaDuatXnMFTZCcv5p1wr6X0EyUXIyGpb8joIPdOuoeS+jItwNUlO8fEYNeLjOguMASoP57oPEXLfuSj3beMJQpM7FyM7qkx4Hn7fDcKct8Dkrg5ef1dxWem0f1hgtGwJzsAtHET/DK6TRS7GwSRVhB8jxBKOgeMc+q1lt9mWPBvpCYfeKVB4J1okOM5/CDAAGWZFCtyn42oAAAAASUVORK5CYII=",
661
+ streaming: "iVBORw0KGgoAAAANSUhEUgAAAD4AAAA+CAYAAABzwahEAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDcuMS1jMDAwIDc5Ljk4ZDc5NDIsIDIwMjIvMDMvMjEtMTE6NDA6NTkgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCAyMi41IChXaW5kb3dzKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo1RkRGQUY4RTkyRTcxMUVEOTAwNEM4Qzk3MjIyQTAzRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo1RkRGQUY4RjkyRTcxMUVEOTAwNEM4Qzk3MjIyQTAzRSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjVGREZBRjhDOTJFNzExRUQ5MDA0QzhDOTcyMjJBMDNFIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjVGREZBRjhEOTJFNzExRUQ5MDA0QzhDOTcyMjJBMDNFIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+4FcVmgAAA6ZJREFUeNrsmktsjFEUx2+laUtQERuRFG2nqC7I2NjprFhhEqLSECoWrNQrXiPGKwQ7EgkikRiPhOXY0FpZGFGpFi1as2AjoghjUo//yZyGhYzvce6937TfSX6bZr5zz//rvd8959xb1hY9r8aijVNj1ELhofBQeCg8FD6arNzAGI2gGUTBXFADJoJqMAS+gCx4Dh6BDtBbqsJngjawFtQV+V01MwMsBhv476/AVXAJDJbCVK8Hl8FLcOA/ootZHT/fz/7qgyq8ChwC3WC94EwqZ3/d7L8qSMIj4AFISAb2jxeb4HEiQRBOH62HYIGhjzGNk+FxrQmPgzR/nEzaZB43bkN4DKRApaVtuJLHj5kUTmvsFqiwnINUcBwNJoTTm75uYXoXywOuefmouhW+FywMWPZJ8ezRKZySiF0BTb13u01y3AhPephSy0zk3bwEkzqE14JVHgK6w1NxB/ioWTzFN1ta+CYfaWgenObd4BwY1lhwbZYW3iIQ2HuwlWdApybxLZLC54FZgsE95ZQzzlWcdDncKCU8pum/cxvMBzu5GSFlzVLCoxo/SLT+T3H2RU2HnwI+F0kJn2NgO3rHHRsK+r5PXw1SwmsNJiKPeapSyyrrY52LCJ9qOAv7xZUXNSb3e1j/k6SE26rCvoGjvNRS/EKc1usiwvOW8/C3PPXbHf7+k5TwD5aFTwdXwBmHv/8sJfy1JcHjwT7QB1pBmcPnslLC+yyIXq0KJytHVOHUxY29kBKeMdxUoCMk6vLUePSRkRLeYWgdX+Sgl/j01SklnBoJbzQJpq1yO3gGNir/fX6Ks0eyLE1pEL2Sg6RcXap56ThOp8IvCDYQqGy8qwqtYcnDwB8cp6hwOra96TOwaeAseKKp1L3BcYoKJ6NDu+8eAqKW0DZVOPLdovScyVNcB9084EY4dUtOuAxoKf+HKeuaonFXOMkvVotwsuNcOjq1tHLYCvJZyh5z+5Bb4TmwRhXurgTBhjienG7hIylsPABVW57j8JRSe00Y7nHhkLcoupXjUCaFK97eljutfwWNxlvhd3v1myLSERE1CLsMie7i8dJ+HUlc/qFthO6oJT3u80736SSP0y/hUOq6V44TiCbulkilt8Psr4n956TepPQFP0py1qnCAeFhMODRzwA/H2F/0kdN2q50DnKKm+AEhnLzkbus1PeeoP7cZf3K5eTfd1l7dH8sTFzi7VVmLgdYneolY6HwUHgoPBQeCg+FjwL7LcAAc/CpEwrVegIAAAAASUVORK5CYII="
662
+ }
663
+ };
664
+
665
+ // Src/Utils/ProfileImage/constants.ts
666
+ var { otherImgs, statusImgs } = ProfileImage_files_default;
667
+ var alphaValue = 0.4;
668
+ var clydeID = "1081004946872352958";
669
+
670
+ // Src/Utils/ProfileImage/badges.ts
671
+ async function getBadges(data, options) {
672
+ const { assets } = data;
673
+ const badges = [...assets?.badges || []];
674
+ const canvasBadges = [];
675
+ for (const badge of badges.reverse()) {
676
+ const { name, icon } = badge;
677
+ const canvas = await (0, import_canvas4.loadImage)(icon).catch(() => void 0);
678
+ if (!canvas) {
679
+ throw new KiraError(
680
+ `Could not load badge: (${name})
681
+ If you think it is not a network problem, please report it in our discord: https://discord.gg/csedxqGQKP`,
682
+ "ASSET_LOAD" /* AssetLoad */
683
+ );
684
+ }
685
+ canvasBadges.push({ canvas, x: 0, y: 15, w: 60 });
686
+ }
687
+ if (options?.customBadges?.length) {
688
+ if (options?.overwriteBadges) {
689
+ canvasBadges.splice(0, badges.length);
690
+ }
691
+ for (let i = 0; i < options.customBadges.length; i++) {
692
+ const canvas = await (0, import_canvas4.loadImage)(parsePng(options.customBadges[i])).catch(() => void 0);
693
+ if (!canvas) {
694
+ const truncatedBadge = truncateText(options.customBadges[i], 30);
695
+ throw new KiraError(
696
+ `Could not load custom badge: (${truncatedBadge}), make sure that the image exists.`,
697
+ "ASSET_LOAD" /* AssetLoad */
698
+ );
699
+ }
700
+ canvasBadges.push({ canvas, x: 10, y: 22, w: 46 });
701
+ }
702
+ }
703
+ return canvasBadges;
704
+ }
705
+ async function genBadges(badges) {
706
+ const canvas = (0, import_canvas4.createCanvas)(885, 303);
707
+ const ctx = canvas.getContext("2d");
708
+ let x = 800;
709
+ for (const badge of badges) {
710
+ const { canvas: badgeCanvas, x: bX, y, w } = badge;
711
+ const ratio = badgeCanvas.height / badgeCanvas.width;
712
+ const drawH = w * ratio;
713
+ ctx.drawImage(badgeCanvas, x + bX, y + (w - drawH) / 2, w, drawH);
714
+ x -= 59;
715
+ }
716
+ return canvas;
717
+ }
718
+ async function genBotVerifBadge(data, badgeX, badgeY) {
719
+ const { basicInfo } = data;
720
+ const { id, verified } = basicInfo;
721
+ const canvas = (0, import_canvas4.createCanvas)(885, 303);
722
+ const ctx = canvas.getContext("2d");
723
+ const isClyde = id === clydeID;
724
+ const badgeName = isClyde ? "botAI" : verified ? "botVerif" : "botNoVerif";
725
+ const botBadgeBase64 = otherImgs[badgeName];
726
+ const botBagde = await (0, import_canvas4.loadImage)(Buffer.from(botBadgeBase64, "base64"));
727
+ ctx.drawImage(botBagde, badgeX, badgeY);
728
+ return canvas;
729
+ }
730
+
731
+ // Src/Utils/ProfileImage/frame.ts
732
+ var import_canvas5 = require("@napi-rs/canvas");
733
+ async function genBase(options, avatarData, bannerData) {
734
+ const canvas = (0, import_canvas5.createCanvas)(885, 303);
735
+ const ctx = canvas.getContext("2d");
736
+ let isBannerLoaded = true;
737
+ let cardBackground = await (0, import_canvas5.loadImage)(
738
+ options?.customBackground ? parseImg(options.customBackground) : bannerData ?? avatarData
739
+ ).catch(() => void 0);
740
+ if (!cardBackground) {
741
+ cardBackground = await (0, import_canvas5.loadImage)(avatarData).catch(() => void 0);
742
+ isBannerLoaded = false;
743
+ }
744
+ const condAvatar = options?.customBackground ? true : !isBannerLoaded ? false : bannerData !== null;
745
+ const wX = condAvatar ? 885 : 900;
746
+ const wY = condAvatar ? 303 : wX;
747
+ const cY = condAvatar ? 0 : -345;
748
+ ctx.fillStyle = "#18191c";
749
+ ctx.beginPath();
750
+ ctx.fillRect(0, 0, 885, 303);
751
+ ctx.fill();
752
+ ctx.filter = (options?.moreBackgroundBlur ? "blur(9px)" : options?.disableBackgroundBlur ? "blur(0px)" : "blur(3px)") + (options?.backgroundBrightness ? ` brightness(${options.backgroundBrightness + 100}%)` : "");
753
+ ctx.drawImage(cardBackground, 0, cY, wX, wY);
754
+ ctx.globalAlpha = 0.2;
755
+ ctx.fillStyle = "#2a2d33";
756
+ ctx.beginPath();
757
+ ctx.fillRect(0, 0, 885, 303);
758
+ ctx.fill();
759
+ return canvas;
760
+ }
761
+ async function genFrame(badges, options) {
762
+ const canvas = (0, import_canvas5.createCanvas)(885, 303);
763
+ const ctx = canvas.getContext("2d");
764
+ const cardFrame = await (0, import_canvas5.loadImage)(Buffer.from(otherImgs.frame, "base64"));
765
+ ctx.globalCompositeOperation = "source-out";
766
+ ctx.globalAlpha = 0.5;
767
+ ctx.drawImage(cardFrame, 0, 0, 885, 303);
768
+ ctx.globalCompositeOperation = "source-over";
769
+ ctx.globalAlpha = alphaValue;
770
+ ctx.fillStyle = "#000";
771
+ ctx.beginPath();
772
+ ctx.roundRect(696, 248, 165, 33, [12]);
773
+ ctx.fill();
774
+ ctx.globalAlpha = 1;
775
+ const badgesLength = badges.length;
776
+ if (options?.badgesFrame && badgesLength > 0 && !options?.removeBadges) {
777
+ ctx.fillStyle = "#000";
778
+ ctx.globalAlpha = alphaValue;
779
+ ctx.beginPath();
780
+ ctx.roundRect(857 - badgesLength * 59, 15, 59 * badgesLength + 8, 61, [17]);
781
+ ctx.fill();
782
+ }
783
+ return canvas;
784
+ }
785
+ async function genBorder(borderColors, options) {
786
+ const canvas = (0, import_canvas5.createCanvas)(885, 303);
787
+ const ctx = canvas.getContext("2d");
788
+ if (borderColors.length > 20)
789
+ throw new KiraError(
790
+ `Invalid borderColor length (${borderColors.length}) must be a maximum of 20 colors`
791
+ );
792
+ const gradX = options.borderAllign == "vertical" ? 0 : 885;
793
+ const gradY = options.borderAllign == "vertical" ? 303 : 0;
794
+ const grd = ctx.createLinearGradient(0, 0, gradX, gradY);
795
+ for (let i = 0; i < borderColors.length; i++) {
796
+ const stop = borderColors.length === 1 ? 0 : i / (borderColors.length - 1);
797
+ grd.addColorStop(stop, parseHex(borderColors[i]));
798
+ }
799
+ ctx.fillStyle = grd;
800
+ ctx.beginPath();
801
+ ctx.fillRect(0, 0, 885, 303);
802
+ ctx.globalCompositeOperation = "destination-out";
803
+ ctx.beginPath();
804
+ ctx.roundRect(9, 9, 867, 285, [25]);
805
+ ctx.fill();
806
+ return canvas;
807
+ }
808
+
809
+ // Src/Utils/ProfileImage/avatar.ts
810
+ var import_canvas6 = require("@napi-rs/canvas");
811
+ async function genNameplate(data) {
812
+ const canvas = (0, import_canvas6.createCanvas)(885, 303);
813
+ const ctx = canvas.getContext("2d");
814
+ const nameplate = data?.decoration?.nameplate;
815
+ if (!nameplate) return canvas;
816
+ const image = await (0, import_canvas6.loadImage)(nameplate.imageURL).catch(() => void 0);
817
+ if (!image) return canvas;
818
+ ctx.save();
819
+ ctx.beginPath();
820
+ ctx.roundRect(280, 20, 585, 260, [20]);
821
+ ctx.clip();
822
+ ctx.globalAlpha = 0.5;
823
+ ctx.drawImage(image, 280, 20, 585, 260);
824
+ ctx.restore();
825
+ return canvas;
826
+ }
827
+ async function genAvatarFrame(data, options) {
828
+ let canvas = (0, import_canvas6.createCanvas)(885, 303);
829
+ const ctx = canvas.getContext("2d");
830
+ const frameUrl = data?.decoration?.avatarFrame;
831
+ const avatarFrame = await (0, import_canvas6.loadImage)(frameUrl);
832
+ ctx.drawImage(avatarFrame, 25, 18, 269, 269);
833
+ if (options?.presenceStatus) {
834
+ canvas = await cutAvatarStatus(canvas, options);
835
+ }
836
+ return canvas;
837
+ }
838
+ async function cutAvatarStatus(canvasToEdit, options) {
839
+ const canvas = (0, import_canvas6.createCanvas)(885, 303);
840
+ const ctx = canvas.getContext("2d");
841
+ const cX = options.presenceStatus == "phone" ? 224.5 : 212;
842
+ const cY = options.presenceStatus == "phone" ? 202 : 204;
843
+ ctx.drawImage(canvasToEdit, 0, 0);
844
+ ctx.globalCompositeOperation = "destination-out";
845
+ if (options.presenceStatus == "phone") ctx.roundRect(cX - 8, cY - 8, 57, 78, [10]);
846
+ else ctx.roundRect(212, 204, 62, 62, [62]);
847
+ ctx.fill();
848
+ ctx.globalCompositeOperation = "source-over";
849
+ return canvas;
850
+ }
851
+ async function genStatus(canvasToEdit, options) {
852
+ const canvas = (0, import_canvas6.createCanvas)(885, 303);
853
+ const ctx = canvas.getContext("2d");
854
+ const validStatus = ["idle", "dnd", "online", "invisible", "offline", "streaming", "phone"];
855
+ if (!validStatus.includes(options.presenceStatus))
856
+ throw new KiraError(
857
+ `Invalid presenceStatus ('${options.presenceStatus}') must be 'online' | 'idle' | 'offline' | 'dnd' | 'invisible' | 'streaming' | 'phone'`
858
+ );
859
+ const statusString = options.presenceStatus == "offline" ? "invisible" : options.presenceStatus;
860
+ const status = await (0, import_canvas6.loadImage)(Buffer.from(statusImgs[statusString], "base64"));
861
+ const cX = options.presenceStatus == "phone" ? 224.5 : 212;
862
+ const cY = options.presenceStatus == "phone" ? 202 : 204;
863
+ ctx.drawImage(canvasToEdit, 0, 0);
864
+ ctx.globalCompositeOperation = "destination-out";
865
+ if (options.presenceStatus == "phone") ctx.roundRect(cX - 8, cY - 8, 57, 78, [10]);
866
+ else ctx.roundRect(212, 204, 62, 62, [62]);
867
+ ctx.fill();
868
+ ctx.globalCompositeOperation = "source-over";
869
+ ctx.drawImage(status, cX, cY);
870
+ return canvas;
871
+ }
872
+
873
+ // Src/Utils/ProfileImage/textAvatar.ts
874
+ var import_canvas7 = require("@napi-rs/canvas");
875
+ async function genTextAndAvatar(data, options, avatarData) {
876
+ const { basicInfo } = data;
877
+ const { globalName, username: rawUsername, discriminator, bot, createdTimestamp, id } = basicInfo;
878
+ const isClyde = id === clydeID;
879
+ const pixelLength = bot ? 470 : 555;
880
+ let canvas = (0, import_canvas7.createCanvas)(885, 303);
881
+ const ctx = canvas.getContext("2d");
882
+ const fixedUsername = options?.customUsername || globalName || rawUsername;
883
+ const { username, newSize } = parseUsername(
884
+ fixedUsername,
885
+ ctx,
886
+ "Helvetica Bold",
887
+ "80",
888
+ pixelLength
889
+ );
890
+ if (options?.customSubtitle && !options.rankData) {
891
+ ctx.globalAlpha = alphaValue;
892
+ ctx.fillStyle = "#2a2d33";
893
+ ctx.beginPath();
894
+ ctx.roundRect(304, 248, 380, 33, [12]);
895
+ ctx.fill();
896
+ ctx.globalAlpha = 1;
897
+ ctx.font = withFallback("23px Helvetica");
898
+ ctx.textAlign = "left";
899
+ ctx.fillStyle = options?.color ? options.color : "#dadada";
900
+ ctx.fillText(`${options?.customSubtitle}`, 314, 273);
901
+ }
902
+ const createdDateString = getDateOrString(
903
+ options?.customDate,
904
+ createdTimestamp,
905
+ options?.localDateType
906
+ );
907
+ if (isClyde && !options?.customTag) {
908
+ options.customTag = "@clyde";
909
+ }
910
+ const tag = options?.customTag ? isString(options.customTag, "customTag") : !discriminator ? `@${rawUsername}` : `#${discriminator}`;
911
+ ctx.font = withFallback(`${newSize}px Helvetica Bold`);
912
+ ctx.textAlign = "left";
913
+ ctx.fillStyle = options?.usernameColor ? parseHex(options.usernameColor) : "#FFFFFF";
914
+ ctx.fillText(username, 300, 155);
915
+ const usernameWidth = ctx.measureText(username).width;
916
+ let verifBadgeX = 300 + usernameWidth + 10;
917
+ let verifBadgeY = 110;
918
+ const useCompactTag = options?.compactTag ?? bot;
919
+ if (useCompactTag) {
920
+ const tagFontSize = Math.round(newSize * 0.32);
921
+ const tagX = 300 + usernameWidth + 8;
922
+ if (bot) {
923
+ const pillHeight = 36;
924
+ const gap = 6;
925
+ const tagCapHeight = tagFontSize * 0.716;
926
+ const usernameCenterY = 155 - newSize * 0.358;
927
+ const blockHeight = pillHeight + gap + tagCapHeight;
928
+ const blockTop = Math.round(usernameCenterY - blockHeight / 2);
929
+ verifBadgeX = tagX;
930
+ verifBadgeY = blockTop;
931
+ const tagY = Math.round(blockTop + pillHeight + gap + tagCapHeight);
932
+ ctx.font = withFallback(`${tagFontSize}px Helvetica Bold`);
933
+ ctx.fillStyle = options?.tagColor ? parseHex(options.tagColor) : "#dadada";
934
+ ctx.fillText(tag, tagX, tagY);
935
+ if (!options?.removeServerTag && data?.decoration?.serverTag) {
936
+ await genServerTag(
937
+ ctx,
938
+ data.decoration.serverTag,
939
+ tagX + ctx.measureText(tag).width,
940
+ tagY + 24
941
+ );
942
+ }
943
+ } else {
944
+ const tagY = 155 - Math.round(newSize * 0.42);
945
+ ctx.font = withFallback(`${tagFontSize}px Helvetica Bold`);
946
+ ctx.fillStyle = options?.tagColor ? parseHex(options.tagColor) : "#dadada";
947
+ ctx.fillText(tag, tagX, tagY);
948
+ const tagWidth = ctx.measureText(tag).width;
949
+ verifBadgeX = tagX + tagWidth + 10;
950
+ if (!options?.removeServerTag && data?.decoration?.serverTag) {
951
+ await genServerTag(ctx, data.decoration.serverTag, tagX + tagWidth, tagY + 24);
952
+ }
953
+ }
954
+ } else if (!options?.rankData) {
955
+ ctx.font = withFallback("60px Helvetica");
956
+ ctx.fillStyle = options?.tagColor ? parseHex(options.tagColor) : "#dadada";
957
+ ctx.fillText(tag, 300, 215);
958
+ if (!options?.removeServerTag && data?.decoration?.serverTag) {
959
+ await genServerTag(ctx, data.decoration.serverTag, 300 + ctx.measureText(tag).width, 215);
960
+ }
961
+ }
962
+ ctx.font = withFallback("23px Helvetica");
963
+ ctx.textAlign = "center";
964
+ ctx.fillStyle = "#dadada";
965
+ ctx.fillText(createdDateString, 775, 273);
966
+ const cardAvatar = await (0, import_canvas7.loadImage)(avatarData);
967
+ const roundValue = options?.squareAvatar ? 30 : 225;
968
+ ctx.beginPath();
969
+ ctx.roundRect(47, 39, 225, 225, [roundValue]);
970
+ ctx.clip();
971
+ ctx.fillStyle = "#292b2f";
972
+ ctx.beginPath();
973
+ ctx.roundRect(47, 39, 225, 225, [roundValue]);
974
+ ctx.fill();
975
+ ctx.drawImage(cardAvatar, 47, 39, 225, 225);
976
+ ctx.closePath();
977
+ if (options?.presenceStatus) {
978
+ canvas = await genStatus(canvas, options);
979
+ }
980
+ return { canvas, verifBadgeX, verifBadgeY };
981
+ }
982
+ async function genServerTag(ctx, serverTag, anchorX, baselineY) {
983
+ const { text, badgeURL } = serverTag;
984
+ const label = text.toUpperCase();
985
+ ctx.font = withFallback("20px Helvetica Bold");
986
+ const labelWidth = ctx.measureText(label).width;
987
+ const badgeSize = badgeURL ? 18 : 0;
988
+ const paddingX = 10;
989
+ const gap = badgeURL ? 6 : 0;
990
+ const pillHeight = 28;
991
+ const pillWidth = paddingX * 2 + badgeSize + gap + labelWidth;
992
+ const pillX = Math.max(10, Math.min(anchorX + 14, 885 - pillWidth - 10));
993
+ const pillY = baselineY - pillHeight + 6;
994
+ ctx.globalAlpha = alphaValue;
995
+ ctx.fillStyle = "#000";
996
+ ctx.beginPath();
997
+ ctx.roundRect(pillX, pillY, pillWidth, pillHeight, [10]);
998
+ ctx.fill();
999
+ ctx.globalAlpha = 1;
1000
+ let cursorX = pillX + paddingX;
1001
+ const badgeImage = badgeURL ? await (0, import_canvas7.loadImage)(badgeURL).catch(() => void 0) : void 0;
1002
+ if (badgeImage) {
1003
+ ctx.drawImage(badgeImage, cursorX, pillY + (pillHeight - badgeSize) / 2, badgeSize, badgeSize);
1004
+ cursorX += badgeSize + gap;
1005
+ }
1006
+ ctx.textAlign = "left";
1007
+ ctx.fillStyle = "#dadada";
1008
+ ctx.fillText(label, cursorX, pillY + pillHeight / 2 + 7);
1009
+ }
1010
+
1011
+ // Src/Utils/ProfileImage/xpBar.ts
1012
+ var import_canvas8 = require("@napi-rs/canvas");
1013
+ function genXpBar(options) {
1014
+ const { currentXp, requiredXp, level, rank, barColor, levelColor, autoColorRank } = options.rankData;
1015
+ if (isNaN(currentXp) || isNaN(requiredXp) || isNaN(level)) {
1016
+ throw new KiraError("rankData options requires: currentXp, requiredXp and level properties");
1017
+ }
1018
+ const canvas = (0, import_canvas8.createCanvas)(885, 303);
1019
+ const ctx = canvas.getContext("2d");
1020
+ const mY = 8;
1021
+ ctx.fillStyle = "#000";
1022
+ ctx.globalAlpha = alphaValue;
1023
+ ctx.beginPath();
1024
+ ctx.roundRect(304, 248, 380, 33, [12]);
1025
+ ctx.fill();
1026
+ ctx.globalAlpha = 1;
1027
+ const rankString = !isNaN(rank) ? `RANK #${abbreviateNumber(isNumber(rank, "rankData:rank"))}` : "";
1028
+ const lvlString = !isNaN(level) ? `Lvl ${abbreviateNumber(isNumber(level, "rankData:level"))}` : "";
1029
+ ctx.font = withFallback("21px Helvetica");
1030
+ ctx.textAlign = "left";
1031
+ ctx.fillStyle = "#dadada";
1032
+ ctx.fillText(`${abbreviateNumber(currentXp)} / ${abbreviateNumber(requiredXp)} XP`, 314, 273);
1033
+ const rankColors = {
1034
+ gold: "#F1C40F",
1035
+ silver: "#a1a4c9",
1036
+ bronze: "#AD8A56",
1037
+ current: "#dadada"
1038
+ };
1039
+ const rankMapping = {
1040
+ "RANK #1": rankColors.gold,
1041
+ "RANK #2": rankColors.silver,
1042
+ "RANK #3": rankColors.bronze
1043
+ };
1044
+ if (autoColorRank && Object.prototype.hasOwnProperty.call(rankMapping, rankString)) {
1045
+ rankColors.current = rankMapping[rankString];
1046
+ }
1047
+ ctx.font = withFallback("bold 21px Helvetica");
1048
+ ctx.textAlign = "right";
1049
+ ctx.fillStyle = rankColors.current;
1050
+ ctx.fillText(`${rankString}`, 674 - ctx.measureText(lvlString).width - 10, 273);
1051
+ ctx.font = withFallback("bold 21px Helvetica");
1052
+ ctx.textAlign = "right";
1053
+ ctx.fillStyle = levelColor ? parseHex(levelColor) : "#dadada";
1054
+ ctx.fillText(`${lvlString}`, 674, 273);
1055
+ ctx.globalAlpha = alphaValue;
1056
+ ctx.fillStyle = "#000";
1057
+ ctx.beginPath();
1058
+ ctx.roundRect(304, 187 - mY, 557, 36, [14]);
1059
+ ctx.fill();
1060
+ ctx.globalAlpha = 1;
1061
+ ctx.beginPath();
1062
+ ctx.roundRect(304, 187 - mY, 557, 36, [14]);
1063
+ ctx.clip();
1064
+ const barColors = resolveCardColors({ custom: barColor });
1065
+ if (barColors.length > 20)
1066
+ throw new KiraError(
1067
+ `Invalid barColor length (${barColors.length}) must be a maximum of 20 colors`
1068
+ );
1069
+ const barWidth = Math.round(currentXp * 556 / requiredXp);
1070
+ const grd = ctx.createLinearGradient(304, 197, 860, 197);
1071
+ for (let i = 0; i < barColors.length; i++) {
1072
+ const stop = barColors.length === 1 ? 0 : i / (barColors.length - 1);
1073
+ grd.addColorStop(stop, parseHex(barColors[i]));
1074
+ }
1075
+ ctx.fillStyle = barColors.length ? grd : "#fff";
1076
+ ctx.beginPath();
1077
+ ctx.roundRect(304, 187 - mY, barWidth, 36, [14]);
1078
+ ctx.fill();
1079
+ return canvas;
1080
+ }
1081
+ function addShadow(canvasToEdit) {
1082
+ const canvas = (0, import_canvas8.createCanvas)(885, 303);
1083
+ const ctx = canvas.getContext("2d");
1084
+ ctx.filter = "drop-shadow(0px 4px 4px #000)";
1085
+ ctx.globalAlpha = alphaValue;
1086
+ ctx.drawImage(canvasToEdit, 0, 0);
1087
+ return canvas;
1088
+ }
1089
+
1090
+ // Src/Utils/output.utils.ts
1091
+ var MIME_MAP = {
1092
+ png: "image/png",
1093
+ jpeg: "image/jpeg",
1094
+ webp: "image/webp"
1095
+ };
1096
+ var DEFAULT_QUALITY = 90;
1097
+ async function encodeCanvas(canvas, output) {
1098
+ const format = output?.format ?? "png";
1099
+ const mime = MIME_MAP[format];
1100
+ if (!mime) {
1101
+ throw new KiraError(
1102
+ `Invalid output format ('${output?.format}'), must be one of: png, jpeg, webp`,
1103
+ "VALIDATION" /* Validation */
1104
+ );
1105
+ }
1106
+ if (format === "png") {
1107
+ return canvas.toBuffer("image/png");
1108
+ }
1109
+ const quality = output?.quality ?? DEFAULT_QUALITY;
1110
+ if (!Number.isFinite(quality) || quality < 1 || quality > 100) {
1111
+ throw new KiraError(
1112
+ `Invalid output quality (${output?.quality}), must be a number between 1 and 100`,
1113
+ "VALIDATION" /* Validation */
1114
+ );
1115
+ }
1116
+ return canvas.toBuffer(mime, quality);
1117
+ }
1118
+ function extensionForFormat(format) {
1119
+ if (format === "jpeg") return "jpg";
1120
+ if (format === "webp") return "webp";
1121
+ return "png";
1122
+ }
1123
+
1124
+ // Src/Utils/profileImage.output.utils.ts
1125
+ ensureFontsRegistered();
1126
+ async function genPng(data, options) {
1127
+ const { basicInfo, assets } = data;
1128
+ const canvas = (0, import_canvas9.createCanvas)(885, 303);
1129
+ const ctx = canvas.getContext("2d");
1130
+ const userAvatar = (assets.avatarURL ?? assets.defaultAvatarURL) + "?size=512";
1131
+ const userBanner = assets.bannerURL ? assets.bannerURL + "?size=512" : null;
1132
+ const badges = await getBadges(data, options);
1133
+ if (options?.removeBorder) ctx.roundRect(9, 9, 867, 285, [26]);
1134
+ else ctx.roundRect(0, 0, 885, 303, [34]);
1135
+ ctx.clip();
1136
+ const cardBase = await genBase(options, userAvatar, userBanner);
1137
+ ctx.drawImage(cardBase, 0, 0);
1138
+ const cardFrame = await genFrame(badges, options);
1139
+ ctx.drawImage(cardFrame, 0, 0);
1140
+ if (!options?.removeNameplate && data?.decoration?.nameplate) {
1141
+ const nameplate = await genNameplate(data);
1142
+ ctx.drawImage(nameplate, 0, 0);
1143
+ }
1144
+ const {
1145
+ canvas: cardTextAndAvatar,
1146
+ verifBadgeX,
1147
+ verifBadgeY
1148
+ } = await genTextAndAvatar(data, options, userAvatar);
1149
+ const textAvatarShadow = addShadow(cardTextAndAvatar);
1150
+ ctx.drawImage(textAvatarShadow, 0, 0);
1151
+ ctx.drawImage(cardTextAndAvatar, 0, 0);
1152
+ const usingAutoNitroColors = !options?.removeBorder && typeof options?.borderColor === "undefined" && !options?.disableProfileTheme && Boolean(data?.decoration?.profileColors?.length);
1153
+ if (usingAutoNitroColors && !options?.borderAllign) options.borderAllign = "vertical";
1154
+ const borderColors = resolveCardColors({
1155
+ custom: options?.borderColor,
1156
+ removeBorder: options?.removeBorder,
1157
+ useNitroTheme: !options?.disableProfileTheme,
1158
+ nitroColors: data?.decoration?.profileColors,
1159
+ useRoleColor: options?.useRoleColor,
1160
+ roleColor: data?.decoration?.roleColor
1161
+ });
1162
+ if (borderColors.length > 0) {
1163
+ const border = await genBorder(borderColors, options);
1164
+ ctx.drawImage(border, 0, 0);
1165
+ }
1166
+ if (basicInfo?.bot) {
1167
+ const botVerifBadge = await genBotVerifBadge(data, verifBadgeX, verifBadgeY);
1168
+ const shadowVerifBadge = addShadow(botVerifBadge);
1169
+ ctx.drawImage(shadowVerifBadge, 0, 0);
1170
+ ctx.drawImage(botVerifBadge, 0, 0);
1171
+ }
1172
+ if (!options?.removeBadges) {
1173
+ const cardBadges = await genBadges(badges);
1174
+ const badgesShadow = addShadow(cardBadges);
1175
+ ctx.drawImage(badgesShadow, 0, 0);
1176
+ ctx.drawImage(cardBadges, 0, 0);
1177
+ }
1178
+ if (options?.rankData) {
1179
+ const xpBar = genXpBar(options);
1180
+ ctx.drawImage(xpBar, 0, 0);
1181
+ }
1182
+ if (!options?.removeAvatarFrame && data?.decoration?.avatarFrame) {
1183
+ const avatarFrame = await genAvatarFrame(data, options);
1184
+ ctx.drawImage(avatarFrame, 0, 0);
1185
+ }
1186
+ return encodeCanvas(canvas, options?.output);
1187
+ }
1188
+
1189
+ // Src/Utils/themes.utils.ts
1190
+ var THEMES = {
1191
+ discord: {
1192
+ accentColor: "#5865F2",
1193
+ borderColor: ["#5865F2", "#404EED"],
1194
+ usernameColor: "#FFFFFF",
1195
+ tagColor: "#B5BAC1",
1196
+ messageColor: "#DBDEE1",
1197
+ levelColor: "#5865F2",
1198
+ barColor: ["#5865F2", "#404EED"],
1199
+ glowColor: "#5865F2",
1200
+ heartColor: "#FF4D6D"
1201
+ },
1202
+ midnight: {
1203
+ accentColor: "#7C3AED",
1204
+ borderColor: ["#312E81", "#7C3AED"],
1205
+ usernameColor: "#E0E7FF",
1206
+ tagColor: "#A5B4FC",
1207
+ messageColor: "#C7D2FE",
1208
+ levelColor: "#818CF8",
1209
+ barColor: ["#4338CA", "#7C3AED"],
1210
+ glowColor: "#818CF8",
1211
+ heartColor: "#F472B6"
1212
+ },
1213
+ sunset: {
1214
+ accentColor: "#F97316",
1215
+ borderColor: ["#F97316", "#EC4899"],
1216
+ usernameColor: "#FFF7ED",
1217
+ tagColor: "#FDBA74",
1218
+ messageColor: "#FED7AA",
1219
+ levelColor: "#FB923C",
1220
+ barColor: ["#F97316", "#EC4899"],
1221
+ glowColor: "#FB923C",
1222
+ heartColor: "#EC4899"
1223
+ },
1224
+ neon: {
1225
+ accentColor: "#22D3EE",
1226
+ borderColor: ["#22D3EE", "#D946EF"],
1227
+ usernameColor: "#ECFEFF",
1228
+ tagColor: "#67E8F9",
1229
+ messageColor: "#A5F3FC",
1230
+ levelColor: "#22D3EE",
1231
+ barColor: ["#22D3EE", "#D946EF"],
1232
+ glowColor: "#D946EF",
1233
+ heartColor: "#D946EF"
1234
+ },
1235
+ forest: {
1236
+ accentColor: "#22C55E",
1237
+ borderColor: ["#166534", "#22C55E"],
1238
+ usernameColor: "#F0FDF4",
1239
+ tagColor: "#86EFAC",
1240
+ messageColor: "#BBF7D0",
1241
+ levelColor: "#4ADE80",
1242
+ barColor: ["#166534", "#22C55E"],
1243
+ glowColor: "#4ADE80",
1244
+ heartColor: "#84CC16"
1245
+ },
1246
+ sakura: {
1247
+ accentColor: "#F472B6",
1248
+ borderColor: ["#FBCFE8", "#F472B6"],
1249
+ usernameColor: "#FDF2F8",
1250
+ tagColor: "#F9A8D4",
1251
+ messageColor: "#FBCFE8",
1252
+ levelColor: "#F472B6",
1253
+ barColor: ["#FBCFE8", "#F472B6"],
1254
+ glowColor: "#F9A8D4",
1255
+ heartColor: "#FB7185"
1256
+ },
1257
+ monochrome: {
1258
+ accentColor: "#9CA3AF",
1259
+ borderColor: ["#4B5563", "#D1D5DB"],
1260
+ usernameColor: "#F9FAFB",
1261
+ tagColor: "#9CA3AF",
1262
+ messageColor: "#D1D5DB",
1263
+ levelColor: "#E5E7EB",
1264
+ barColor: ["#4B5563", "#D1D5DB"],
1265
+ glowColor: "#D1D5DB",
1266
+ heartColor: "#9CA3AF"
1267
+ },
1268
+ gold: {
1269
+ accentColor: "#D4AF37",
1270
+ borderColor: ["#3F3F1F", "#D4AF37"],
1271
+ usernameColor: "#FEF9E7",
1272
+ tagColor: "#E9D8A6",
1273
+ messageColor: "#F5E6B8",
1274
+ levelColor: "#D4AF37",
1275
+ barColor: ["#3F3F1F", "#D4AF37"],
1276
+ glowColor: "#D4AF37",
1277
+ heartColor: "#D4AF37"
1278
+ }
1279
+ };
1280
+ function getThemePalette(theme) {
1281
+ if (!theme) return void 0;
1282
+ const palette = THEMES[theme];
1283
+ if (!palette) {
1284
+ throw new KiraError(
1285
+ `Invalid theme ('${theme}'), must be one of: ${Object.keys(THEMES).join(", ")}`,
1286
+ "VALIDATION" /* Validation */
1287
+ );
1288
+ }
1289
+ return palette;
1290
+ }
1291
+
1292
+ // Src/Cards/profileImage.ts
1293
+ async function profileImage(userId, options = {}) {
1294
+ if (!userId || typeof userId !== "string")
1295
+ throw new KiraError(
1296
+ `TypeError: Invalid argument for profileImage()
1297
+ Expected string userId, got ${typeof userId === "undefined" || !userId ? "undefined" : typeof userId}`,
1298
+ "VALIDATION" /* Validation */
1299
+ );
1300
+ const data = await fetchUserData(userId, options.guildId, options.bypassCache);
1301
+ const palette = getThemePalette(options.theme);
1302
+ const resolvedOptions = {
1303
+ ...options,
1304
+ usernameColor: options.usernameColor ?? palette?.usernameColor,
1305
+ tagColor: options.tagColor ?? palette?.tagColor,
1306
+ borderColor: options.borderColor ?? palette?.borderColor
1307
+ };
1308
+ if (resolvedOptions.rankData) {
1309
+ resolvedOptions.rankData = {
1310
+ ...resolvedOptions.rankData,
1311
+ barColor: resolvedOptions.rankData.barColor ?? palette?.barColor,
1312
+ levelColor: resolvedOptions.rankData.levelColor ?? palette?.levelColor
1313
+ };
1314
+ }
1315
+ try {
1316
+ const buffer = await genPng(data, resolvedOptions);
1317
+ return buffer;
1318
+ } catch (error) {
1319
+ if (error instanceof KiraError) throw error;
1320
+ const message = error instanceof Error ? error.message : String(error);
1321
+ if (message.includes("source rejected")) {
1322
+ throw new KiraError(`Error loading user assets, try again later`, "ASSET_LOAD" /* AssetLoad */);
1323
+ }
1324
+ throw new KiraError(message, "RENDER" /* Render */);
1325
+ }
1326
+ }
1327
+
1328
+ // Src/Utils/LeaderboardImage/constants.ts
1329
+ var CARD_WIDTH = 720;
1330
+ var ROW_HEIGHT = 100;
1331
+ var ROW_GAP = 14;
1332
+ var PADDING = 26;
1333
+ var CORNER_RADIUS = 28;
1334
+ var RANK_COLORS = {
1335
+ 1: "#F1C40F",
1336
+ 2: "#B9BBC6",
1337
+ 3: "#D08A3E"
1338
+ };
1339
+ var DEFAULT_ACCENT = "#2DD4BF";
1340
+
1341
+ // Src/Utils/LeaderboardImage/colorUtils.ts
1342
+ function hexToRgb2(hex) {
1343
+ const normalized = parseHex(hex).replace("#", "");
1344
+ const full = normalized.length === 3 ? normalized.split("").map((c) => c + c).join("") : normalized;
1345
+ return {
1346
+ r: parseInt(full.slice(0, 2), 16),
1347
+ g: parseInt(full.slice(2, 4), 16),
1348
+ b: parseInt(full.slice(4, 6), 16)
1349
+ };
1350
+ }
1351
+ function hexToRgba2(hex, alpha) {
1352
+ const { r, g, b } = hexToRgb2(hex);
1353
+ return `rgba(${r}, ${g}, ${b}, ${alpha})`;
1354
+ }
1355
+
1356
+ // Src/Utils/LeaderboardImage/dimensions.ts
1357
+ var import_canvas10 = require("@napi-rs/canvas");
1358
+ function getHeaderHeight(hasTitle, hasSubtitle) {
1359
+ if (!hasTitle) return 0;
1360
+ return hasSubtitle ? 96 : 68;
1361
+ }
1362
+ function getCardHeight(rowCount, hasTitle, hasSubtitle) {
1363
+ const header = getHeaderHeight(hasTitle, hasSubtitle);
1364
+ return PADDING * 2 + header + rowCount * ROW_HEIGHT + Math.max(0, rowCount - 1) * ROW_GAP;
1365
+ }
1366
+ function createLeaderboardCanvas(height) {
1367
+ const canvas = (0, import_canvas10.createCanvas)(CARD_WIDTH, height);
1368
+ const ctx = canvas.getContext("2d");
1369
+ return { canvas, ctx };
1370
+ }
1371
+
1372
+ // Src/Utils/LeaderboardImage/background.ts
1373
+ var import_canvas11 = require("@napi-rs/canvas");
1374
+ async function drawCardBackground(ctx, width, height, backgroundImage, accentColor = DEFAULT_ACCENT) {
1375
+ ctx.beginPath();
1376
+ ctx.roundRect(0, 0, width, height, [CORNER_RADIUS]);
1377
+ ctx.clip();
1378
+ ctx.fillStyle = "#111318";
1379
+ ctx.fillRect(0, 0, width, height);
1380
+ const image = backgroundImage ? await (0, import_canvas11.loadImage)(backgroundImage).catch(() => void 0) : void 0;
1381
+ if (image) {
1382
+ const scale = Math.max(width / image.width, height / image.height);
1383
+ const drawW = image.width * scale;
1384
+ const drawH = image.height * scale;
1385
+ const dx = (width - drawW) / 2;
1386
+ const dy = (height - drawH) / 2;
1387
+ ctx.filter = "blur(6px) brightness(55%)";
1388
+ ctx.drawImage(image, dx, dy, drawW, drawH);
1389
+ ctx.filter = "none";
1390
+ ctx.fillStyle = "rgba(10, 11, 14, 0.55)";
1391
+ ctx.fillRect(0, 0, width, height);
1392
+ } else {
1393
+ const glowTL = ctx.createRadialGradient(0, 0, 0, 0, 0, width * 0.75);
1394
+ glowTL.addColorStop(0, hexToRgba2(accentColor, 0.16));
1395
+ glowTL.addColorStop(1, "rgba(0, 0, 0, 0)");
1396
+ ctx.fillStyle = glowTL;
1397
+ ctx.fillRect(0, 0, width, height);
1398
+ const glowBR = ctx.createRadialGradient(width, height, 0, width, height, width * 0.6);
1399
+ glowBR.addColorStop(0, hexToRgba2(accentColor, 0.1));
1400
+ glowBR.addColorStop(1, "rgba(0, 0, 0, 0)");
1401
+ ctx.fillStyle = glowBR;
1402
+ ctx.fillRect(0, 0, width, height);
1403
+ ctx.strokeStyle = "rgba(255, 255, 255, 0.035)";
1404
+ ctx.lineWidth = 1;
1405
+ const step = 34;
1406
+ for (let d = -height; d < width; d += step) {
1407
+ ctx.beginPath();
1408
+ ctx.moveTo(d, height);
1409
+ ctx.lineTo(d + height, 0);
1410
+ ctx.stroke();
1411
+ }
1412
+ }
1413
+ const gradient = ctx.createLinearGradient(0, 0, 0, height);
1414
+ gradient.addColorStop(0, "rgba(0, 0, 0, 0)");
1415
+ gradient.addColorStop(1, "rgba(0, 0, 0, 0.35)");
1416
+ ctx.fillStyle = gradient;
1417
+ ctx.fillRect(0, 0, width, height);
1418
+ }
1419
+ function drawCardBorder(ctx, width, height, colors) {
1420
+ const thickness = 3;
1421
+ ctx.save();
1422
+ const grd = ctx.createLinearGradient(0, 0, width, height);
1423
+ for (let i = 0; i < colors.length; i++) {
1424
+ const stop = colors.length === 1 ? 0 : i / (colors.length - 1);
1425
+ grd.addColorStop(stop, parseHex(colors[i]));
1426
+ }
1427
+ ctx.strokeStyle = grd;
1428
+ ctx.shadowColor = hexToRgba2(parseHex(colors[0]), 0.55);
1429
+ ctx.shadowBlur = 18;
1430
+ ctx.lineWidth = thickness;
1431
+ ctx.beginPath();
1432
+ ctx.roundRect(thickness / 2, thickness / 2, width - thickness, height - thickness, [
1433
+ CORNER_RADIUS
1434
+ ]);
1435
+ ctx.stroke();
1436
+ ctx.restore();
1437
+ }
1438
+
1439
+ // Src/Utils/LeaderboardImage/header.ts
1440
+ function drawTrophyIcon(ctx, x, y, size, color) {
1441
+ const s = size / 24;
1442
+ ctx.save();
1443
+ ctx.translate(x, y);
1444
+ ctx.fillStyle = color;
1445
+ ctx.strokeStyle = color;
1446
+ ctx.lineWidth = 2.1 * s;
1447
+ ctx.lineCap = "round";
1448
+ ctx.beginPath();
1449
+ ctx.arc(4 * s, 6.5 * s, 3 * s, Math.PI * 0.15, Math.PI * 1.85, false);
1450
+ ctx.stroke();
1451
+ ctx.beginPath();
1452
+ ctx.arc(20 * s, 6.5 * s, 3 * s, Math.PI * 1.15, Math.PI * 0.85, true);
1453
+ ctx.stroke();
1454
+ ctx.beginPath();
1455
+ ctx.moveTo(7 * s, 3 * s);
1456
+ ctx.lineTo(17 * s, 3 * s);
1457
+ ctx.lineTo(17 * s, 8 * s);
1458
+ ctx.quadraticCurveTo(17 * s, 14.5 * s, 12 * s, 14.5 * s);
1459
+ ctx.quadraticCurveTo(7 * s, 14.5 * s, 7 * s, 8 * s);
1460
+ ctx.closePath();
1461
+ ctx.fill();
1462
+ ctx.fillRect(10.5 * s, 14.5 * s, 3 * s, 3.5 * s);
1463
+ ctx.beginPath();
1464
+ ctx.roundRect(6 * s, 18 * s, 12 * s, 3 * s, [1.5 * s]);
1465
+ ctx.fill();
1466
+ ctx.restore();
1467
+ }
1468
+ function drawHeader(ctx, title, subtitle, accentColor) {
1469
+ const iconSize = 26;
1470
+ const iconY = PADDING + 2;
1471
+ drawTrophyIcon(ctx, PADDING, iconY, iconSize, accentColor);
1472
+ ctx.font = withFallback("30px Helvetica Bold");
1473
+ ctx.textAlign = "left";
1474
+ ctx.fillStyle = "#FFFFFF";
1475
+ ctx.fillText(title, PADDING + iconSize + 14, PADDING + 30);
1476
+ if (subtitle) {
1477
+ ctx.font = withFallback("18px Helvetica");
1478
+ ctx.fillStyle = hexToRgba2(accentColor, 0.85);
1479
+ ctx.fillText(subtitle, PADDING, PADDING + 56);
1480
+ }
1481
+ }
1482
+
1483
+ // Src/Utils/LeaderboardImage/row.ts
1484
+ var import_canvas12 = require("@napi-rs/canvas");
1485
+ async function drawRow(ctx, resolved, rowY, options) {
1486
+ const { entry, data } = resolved;
1487
+ const { basicInfo, assets } = data;
1488
+ const rowColor = RANK_COLORS[entry.rank] ?? (options?.accentColor ? parseHex(options.accentColor) : DEFAULT_ACCENT);
1489
+ const rowWidth = CARD_WIDTH - PADDING * 2;
1490
+ ctx.save();
1491
+ ctx.shadowColor = "rgba(0, 0, 0, 0.35)";
1492
+ ctx.shadowBlur = 16;
1493
+ ctx.shadowOffsetY = 6;
1494
+ ctx.fillStyle = "rgba(18, 20, 26, 0.55)";
1495
+ ctx.beginPath();
1496
+ ctx.roundRect(PADDING, rowY, rowWidth, ROW_HEIGHT, [20]);
1497
+ ctx.fill();
1498
+ ctx.restore();
1499
+ const rowGradient = ctx.createLinearGradient(0, rowY, 0, rowY + ROW_HEIGHT);
1500
+ rowGradient.addColorStop(0, hexToRgba2(rowColor, 0.14));
1501
+ rowGradient.addColorStop(1, hexToRgba2(rowColor, 0.05));
1502
+ ctx.fillStyle = rowGradient;
1503
+ ctx.beginPath();
1504
+ ctx.roundRect(PADDING, rowY, rowWidth, ROW_HEIGHT, [20]);
1505
+ ctx.fill();
1506
+ ctx.strokeStyle = hexToRgba2(rowColor, 0.45);
1507
+ ctx.lineWidth = 1.25;
1508
+ ctx.beginPath();
1509
+ ctx.roundRect(PADDING + 0.75, rowY + 0.75, rowWidth - 1.5, ROW_HEIGHT - 1.5, [20]);
1510
+ ctx.stroke();
1511
+ const circleSize = 60;
1512
+ const circleY = rowY + (ROW_HEIGHT - circleSize) / 2;
1513
+ const rankX = PADDING + 22 + circleSize / 2;
1514
+ ctx.beginPath();
1515
+ ctx.arc(rankX, circleY + circleSize / 2, circleSize / 2, 0, Math.PI * 2);
1516
+ ctx.fillStyle = entry.rank <= 3 ? rowColor : hexToRgba2(rowColor, 0.16);
1517
+ ctx.fill();
1518
+ if (entry.rank > 3) {
1519
+ ctx.strokeStyle = hexToRgba2(rowColor, 0.8);
1520
+ ctx.lineWidth = 2;
1521
+ ctx.beginPath();
1522
+ ctx.arc(rankX, circleY + circleSize / 2, circleSize / 2 - 1, 0, Math.PI * 2);
1523
+ ctx.stroke();
1524
+ }
1525
+ ctx.font = withFallback("bold 24px Helvetica Bold");
1526
+ ctx.textAlign = "center";
1527
+ ctx.fillStyle = entry.rank <= 3 ? "#14151a" : "#f1f2f4";
1528
+ ctx.fillText(`${entry.rank}`, rankX, circleY + circleSize / 2 + 8);
1529
+ const avatarX = PADDING + 22 + circleSize + 20;
1530
+ const avatarUrl = assets.avatarURL ?? assets.defaultAvatarURL;
1531
+ const avatarCx = avatarX + circleSize / 2;
1532
+ const avatarCy = circleY + circleSize / 2;
1533
+ if (entry.rank === 1) {
1534
+ const glow = ctx.createRadialGradient(
1535
+ avatarCx,
1536
+ avatarCy,
1537
+ circleSize / 2,
1538
+ avatarCx,
1539
+ avatarCy,
1540
+ circleSize
1541
+ );
1542
+ glow.addColorStop(0, hexToRgba2(rowColor, 0.35));
1543
+ glow.addColorStop(1, "rgba(0, 0, 0, 0)");
1544
+ ctx.fillStyle = glow;
1545
+ ctx.beginPath();
1546
+ ctx.arc(avatarCx, avatarCy, circleSize, 0, Math.PI * 2);
1547
+ ctx.fill();
1548
+ }
1549
+ ctx.beginPath();
1550
+ ctx.arc(avatarCx, avatarCy, circleSize / 2 + 3, 0, Math.PI * 2);
1551
+ ctx.strokeStyle = rowColor;
1552
+ ctx.lineWidth = 3;
1553
+ ctx.stroke();
1554
+ ctx.beginPath();
1555
+ ctx.arc(avatarCx, avatarCy, circleSize / 2, 0, Math.PI * 2);
1556
+ ctx.fillStyle = "#292b2f";
1557
+ ctx.fill();
1558
+ const avatarImage = await (0, import_canvas12.loadImage)(avatarUrl).catch(() => void 0);
1559
+ if (avatarImage) {
1560
+ ctx.save();
1561
+ ctx.beginPath();
1562
+ ctx.arc(avatarCx, avatarCy, circleSize / 2, 0, Math.PI * 2);
1563
+ ctx.clip();
1564
+ ctx.drawImage(avatarImage, avatarX, circleY, circleSize, circleSize);
1565
+ ctx.restore();
1566
+ }
1567
+ const levelText = `Nv. ${abbreviateNumber(entry.level)}`;
1568
+ ctx.font = withFallback("bold 17px Helvetica Bold");
1569
+ const levelTextWidth = ctx.measureText(levelText).width;
1570
+ const pillPaddingX = 14;
1571
+ const pillWidth = levelTextWidth + pillPaddingX * 2;
1572
+ const pillHeight = 30;
1573
+ const pillX = CARD_WIDTH - PADDING - 16 - pillWidth;
1574
+ const pillY = rowY + 20;
1575
+ ctx.fillStyle = hexToRgba2(rowColor, 0.16);
1576
+ ctx.beginPath();
1577
+ ctx.roundRect(pillX, pillY, pillWidth, pillHeight, [pillHeight / 2]);
1578
+ ctx.fill();
1579
+ ctx.strokeStyle = hexToRgba2(rowColor, 0.7);
1580
+ ctx.lineWidth = 1.5;
1581
+ ctx.beginPath();
1582
+ ctx.roundRect(pillX, pillY, pillWidth, pillHeight, [pillHeight / 2]);
1583
+ ctx.stroke();
1584
+ ctx.font = withFallback("bold 17px Helvetica Bold");
1585
+ ctx.textAlign = "center";
1586
+ ctx.fillStyle = options?.levelColor ? parseHex(options.levelColor) : "#f1f2f4";
1587
+ ctx.fillText(levelText, pillX + pillWidth / 2, pillY + pillHeight / 2 + 6);
1588
+ const textX = avatarX + circleSize + 22;
1589
+ const displayName = truncateText(basicInfo.globalName || basicInfo.username, 22);
1590
+ const maxNameWidth = pillX - 16 - textX;
1591
+ ctx.font = withFallback("21px Helvetica Bold");
1592
+ ctx.textAlign = "left";
1593
+ ctx.fillStyle = options?.usernameColor ? parseHex(options.usernameColor) : "#FFFFFF";
1594
+ ctx.fillText(displayName, textX, rowY + 34, Math.max(maxNameWidth, 40));
1595
+ const barX = textX;
1596
+ const barWidth = CARD_WIDTH - PADDING - 16 - barX;
1597
+ const barY = rowY + 56;
1598
+ const barHeight = 16;
1599
+ ctx.fillStyle = "rgba(0, 0, 0, 0.35)";
1600
+ ctx.beginPath();
1601
+ ctx.roundRect(barX, barY, barWidth, barHeight, [barHeight / 2]);
1602
+ ctx.fill();
1603
+ const progress = entry.requiredXp > 0 ? Math.min(entry.currentXp / entry.requiredXp, 1) : 0;
1604
+ const minVisibleWidth = Math.min(barWidth, barHeight * 2.5);
1605
+ const filledWidth = progress > 0 ? Math.max(minVisibleWidth, Math.round(barWidth * progress)) : 0;
1606
+ const barColors = resolveCardColors({
1607
+ custom: options?.barColor,
1608
+ fallback: [rowColor, hexToRgba2(rowColor, 0.6)]
1609
+ });
1610
+ const grd = ctx.createLinearGradient(barX, 0, barX + filledWidth, 0);
1611
+ for (let i = 0; i < barColors.length; i++) {
1612
+ const stop = barColors.length === 1 ? 0 : i / (barColors.length - 1);
1613
+ grd.addColorStop(stop, barColors[i].startsWith("rgba") ? barColors[i] : parseHex(barColors[i]));
1614
+ }
1615
+ if (progress > 0) {
1616
+ ctx.save();
1617
+ ctx.fillStyle = grd;
1618
+ ctx.beginPath();
1619
+ ctx.roundRect(barX, barY, filledWidth, barHeight, [barHeight / 2]);
1620
+ ctx.fill();
1621
+ ctx.fillStyle = "rgba(255, 255, 255, 0.35)";
1622
+ ctx.beginPath();
1623
+ ctx.roundRect(barX + 3, barY + 2, Math.max(0, filledWidth - 6), barHeight * 0.28, [
1624
+ barHeight / 2
1625
+ ]);
1626
+ ctx.fill();
1627
+ ctx.restore();
1628
+ }
1629
+ ctx.font = withFallback("bold 13px Helvetica");
1630
+ ctx.textAlign = "right";
1631
+ ctx.fillStyle = hexToRgba2("#f1f2f4", 0.85);
1632
+ ctx.fillText(
1633
+ `${abbreviateNumber(entry.currentXp)} / ${abbreviateNumber(entry.requiredXp)} XP`,
1634
+ barX + barWidth,
1635
+ barY + barHeight + 16
1636
+ );
1637
+ }
1638
+
1639
+ // Src/Utils/LeaderboardImage/index.ts
1640
+ ensureFontsRegistered();
1641
+
1642
+ // Src/Utils/leaderboardImage.output.utils.ts
1643
+ ensureFontsRegistered();
1644
+ async function genLeaderboardPng(resolvedEntries, options, borderColors) {
1645
+ const hasTitle = Boolean(options?.title);
1646
+ const hasSubtitle = Boolean(options?.subtitle);
1647
+ const height = getCardHeight(resolvedEntries.length, hasTitle, hasSubtitle);
1648
+ const { canvas, ctx } = createLeaderboardCanvas(height);
1649
+ const accentColor = options?.accentColor ? parseHex(options.accentColor) : DEFAULT_ACCENT;
1650
+ await drawCardBackground(ctx, CARD_WIDTH, height, options?.backgroundImage, accentColor);
1651
+ if (borderColors.length > 0) {
1652
+ drawCardBorder(ctx, CARD_WIDTH, height, borderColors);
1653
+ }
1654
+ if (hasTitle) {
1655
+ drawHeader(ctx, options.title, options.subtitle, accentColor);
1656
+ }
1657
+ const startY = PADDING + getHeaderHeight(hasTitle, hasSubtitle);
1658
+ for (let i = 0; i < resolvedEntries.length; i++) {
1659
+ const rowY = startY + i * (ROW_HEIGHT + ROW_GAP);
1660
+ await drawRow(ctx, resolvedEntries[i], rowY, options);
1661
+ }
1662
+ return encodeCanvas(canvas, options?.output);
1663
+ }
1664
+
1665
+ // Src/Cards/leaderboardImage.ts
1666
+ var DEFAULT_MAX_ENTRIES = 5;
1667
+ var HARD_MAX_ENTRIES = 15;
1668
+ async function leaderboardImage(entries, options = {}) {
1669
+ if (!Array.isArray(entries) || entries.length === 0) {
1670
+ throw new KiraError(
1671
+ "leaderboardImage() expects a non-empty array of LeaderboardEntry",
1672
+ "VALIDATION" /* Validation */
1673
+ );
1674
+ }
1675
+ const requestedMax = options.maxEntries ?? DEFAULT_MAX_ENTRIES;
1676
+ if (!Number.isFinite(requestedMax) || requestedMax < 1) {
1677
+ throw new KiraError(
1678
+ `Invalid maxEntries (${options.maxEntries}), must be a number between 1 and ${HARD_MAX_ENTRIES}`,
1679
+ "VALIDATION" /* Validation */
1680
+ );
1681
+ }
1682
+ const maxEntries = Math.min(requestedMax, HARD_MAX_ENTRIES);
1683
+ const topEntries = entries.slice(0, maxEntries);
1684
+ for (const entry of topEntries) {
1685
+ if (!entry?.userId || typeof entry.userId !== "string") {
1686
+ throw new KiraError(
1687
+ "Every leaderboard entry requires a valid userId",
1688
+ "VALIDATION" /* Validation */
1689
+ );
1690
+ }
1691
+ if (typeof entry.currentXp !== "number" || typeof entry.requiredXp !== "number" || typeof entry.level !== "number" || !Number.isFinite(entry.currentXp) || !Number.isFinite(entry.requiredXp) || !Number.isFinite(entry.level)) {
1692
+ throw new KiraError(
1693
+ `Invalid leaderboard entry for userId (${entry.userId}): currentXp, requiredXp and level are required numbers`,
1694
+ "VALIDATION" /* Validation */
1695
+ );
1696
+ }
1697
+ }
1698
+ const resolvedEntries = await Promise.all(
1699
+ topEntries.map(async (entry, index) => {
1700
+ const data = await fetchUserData(entry.userId, options.guildId, options.bypassCache);
1701
+ return {
1702
+ entry: { ...entry, rank: entry.rank ?? index + 1 },
1703
+ data
1704
+ };
1705
+ })
1706
+ );
1707
+ try {
1708
+ const palette = getThemePalette(options.theme);
1709
+ const accentColor = options.accentColor ?? palette?.accentColor ?? DEFAULT_ACCENT;
1710
+ const topEntryData = resolvedEntries[0]?.data;
1711
+ const borderColors = resolveCardColors({
1712
+ custom: options.borderColor,
1713
+ removeBorder: options.removeBorder,
1714
+ useNitroTheme: options.useNitroTheme,
1715
+ nitroColors: topEntryData?.decoration.profileColors,
1716
+ useRoleColor: options.useRoleColor,
1717
+ roleColor: topEntryData?.decoration.roleColor,
1718
+ fallback: palette?.borderColor ?? [accentColor]
1719
+ });
1720
+ const resolvedOptions = {
1721
+ ...options,
1722
+ accentColor,
1723
+ usernameColor: options.usernameColor ?? palette?.usernameColor,
1724
+ levelColor: options.levelColor ?? palette?.levelColor,
1725
+ barColor: options.barColor ?? palette?.barColor
1726
+ };
1727
+ return await genLeaderboardPng(resolvedEntries, resolvedOptions, borderColors);
1728
+ } catch (error) {
1729
+ if (error instanceof KiraError) throw error;
1730
+ const message = error instanceof Error ? error.message : String(error);
1731
+ throw new KiraError(message, "RENDER" /* Render */);
1732
+ }
1733
+ }
1734
+
1735
+ // Src/Utils/MemberEeventCard/constants.ts
1736
+ var CARD_WIDTH2 = 700;
1737
+ var CORNER_RADIUS2 = 28;
1738
+ var BANNER_HEIGHT = 170;
1739
+ var BASE_AVATAR_SIZE = 172;
1740
+ var AVATAR_BORDER = 6;
1741
+
1742
+ // Src/Utils/MemberEeventCard/dimensions.ts
1743
+ var import_canvas13 = require("@napi-rs/canvas");
1744
+ function normalizeFontScale(fontScale) {
1745
+ return fontScale && fontScale > 0 ? fontScale : 1;
1746
+ }
1747
+ function computeAvatarSize(fontScale) {
1748
+ const scale = 1 + (fontScale - 1) * 0.3;
1749
+ return Math.round(BASE_AVATAR_SIZE * scale);
1750
+ }
1751
+ function computeBodyHeight(hasMessage, hasMemberCount, hasDate, fontScale) {
1752
+ let h = 40 * fontScale;
1753
+ h += 38 * fontScale;
1754
+ if (hasMessage) h += 30 * fontScale;
1755
+ if (hasMemberCount) h += 28 * fontScale;
1756
+ if (hasDate) h += 24 * fontScale;
1757
+ h += 28;
1758
+ return h;
1759
+ }
1760
+ function getCardDimensions(layout) {
1761
+ const hasMessage = Boolean(layout.message);
1762
+ const hasMemberCount = layout.memberCount != null;
1763
+ const hasDate = Boolean(layout.dateText);
1764
+ const fontScale = normalizeFontScale(layout.fontScale);
1765
+ const avatarSize = computeAvatarSize(fontScale);
1766
+ const bodyHeight = computeBodyHeight(hasMessage, hasMemberCount, hasDate, fontScale);
1767
+ const height = Math.round(BANNER_HEIGHT + avatarSize / 2 + bodyHeight);
1768
+ const baseAvatarSize = computeAvatarSize(1);
1769
+ const baseBodyHeight = computeBodyHeight(hasMessage, hasMemberCount, hasDate, 1);
1770
+ const baseHeight = BANNER_HEIGHT + baseAvatarSize / 2 + baseBodyHeight;
1771
+ const aspectRatio = CARD_WIDTH2 / baseHeight;
1772
+ const width = Math.round(height * aspectRatio);
1773
+ return { width, height };
1774
+ }
1775
+ function createMemberEventCanvas(width, height) {
1776
+ const canvas = (0, import_canvas13.createCanvas)(width, height);
1777
+ const ctx = canvas.getContext("2d");
1778
+ return { canvas, ctx };
1779
+ }
1780
+
1781
+ // Src/Utils/MemberEeventCard/render.ts
1782
+ var import_canvas15 = require("@napi-rs/canvas");
1783
+
1784
+ // Src/Utils/MemberEeventCard/textEffects.ts
1785
+ function applyTextEffect(ctx, effect, glowColor) {
1786
+ if (effect === "shadow") {
1787
+ ctx.shadowColor = "rgba(0, 0, 0, 0.65)";
1788
+ ctx.shadowBlur = 6;
1789
+ ctx.shadowOffsetX = 0;
1790
+ ctx.shadowOffsetY = 3;
1791
+ } else if (effect === "glow") {
1792
+ ctx.shadowColor = glowColor;
1793
+ ctx.shadowBlur = 20;
1794
+ ctx.shadowOffsetX = 0;
1795
+ ctx.shadowOffsetY = 0;
1796
+ } else {
1797
+ ctx.shadowColor = "transparent";
1798
+ ctx.shadowBlur = 0;
1799
+ ctx.shadowOffsetX = 0;
1800
+ ctx.shadowOffsetY = 0;
1801
+ }
1802
+ }
1803
+
1804
+ // Src/Utils/MemberEeventCard/pills.ts
1805
+ var import_canvas14 = require("@napi-rs/canvas");
1806
+ async function drawServerTagPill(ctx, serverTag) {
1807
+ const text = truncateText(serverTag.text, 12);
1808
+ const iconSize = serverTag.badgeURL ? 18 : 0;
1809
+ const paddingX = 10;
1810
+ const pillHeight = 26;
1811
+ const gap = iconSize ? 6 : 0;
1812
+ ctx.font = withFallback("13px Helvetica Bold");
1813
+ const textWidth = ctx.measureText(text).width;
1814
+ const pillWidth = paddingX * 2 + iconSize + gap + textWidth;
1815
+ const pillX = 16;
1816
+ const pillY = 16;
1817
+ ctx.save();
1818
+ ctx.beginPath();
1819
+ ctx.roundRect(pillX, pillY, pillWidth, pillHeight, [pillHeight / 2]);
1820
+ ctx.fillStyle = "rgba(10, 10, 14, 0.55)";
1821
+ ctx.fill();
1822
+ ctx.restore();
1823
+ let cursorX = pillX + paddingX;
1824
+ if (iconSize && serverTag.badgeURL) {
1825
+ const badgeImage = await (0, import_canvas14.loadImage)(serverTag.badgeURL).catch((_error) => {
1826
+ return void 0;
1827
+ });
1828
+ if (badgeImage) {
1829
+ ctx.drawImage(badgeImage, cursorX, pillY + (pillHeight - iconSize) / 2, iconSize, iconSize);
1830
+ cursorX += iconSize + gap;
1831
+ }
1832
+ }
1833
+ ctx.textAlign = "left";
1834
+ ctx.fillStyle = "#ffffff";
1835
+ ctx.font = withFallback("13px Helvetica Bold");
1836
+ ctx.fillText(text, cursorX, pillY + pillHeight / 2 + 4);
1837
+ }
1838
+ async function drawBadgesPill(ctx, width, badges, maxBadges, iconSize = 20, pillHeight = 32) {
1839
+ const shown = badges.slice(0, maxBadges > 0 ? maxBadges : 3);
1840
+ if (!shown.length) return;
1841
+ const gap = Math.round(iconSize * 0.3);
1842
+ const paddingX = Math.round(iconSize * 0.5);
1843
+ const totalIconsWidth = shown.length * iconSize + (shown.length - 1) * gap;
1844
+ const pillWidth = paddingX * 2 + totalIconsWidth;
1845
+ const pillX = width - 16 - pillWidth;
1846
+ const pillY = 16;
1847
+ ctx.save();
1848
+ ctx.beginPath();
1849
+ ctx.roundRect(pillX, pillY, pillWidth, pillHeight, [pillHeight / 2]);
1850
+ ctx.fillStyle = "rgba(10, 10, 14, 0.55)";
1851
+ ctx.fill();
1852
+ ctx.restore();
1853
+ let cursorX = pillX + paddingX;
1854
+ for (const badge of shown) {
1855
+ const badgeImage = await (0, import_canvas14.loadImage)(badge.icon).catch(() => void 0);
1856
+ if (badgeImage) {
1857
+ ctx.drawImage(badgeImage, cursorX, pillY + (pillHeight - iconSize) / 2, iconSize, iconSize);
1858
+ }
1859
+ cursorX += iconSize + gap;
1860
+ }
1861
+ }
1862
+
1863
+ // Src/Utils/MemberEeventCard/render.ts
1864
+ async function drawMemberEventCard(ctx, width, height, avatarUrl, username, layout) {
1865
+ const fontScale = normalizeFontScale(layout.fontScale);
1866
+ const avatarSize = computeAvatarSize(fontScale);
1867
+ const avatarBorder = Math.max(4, Math.round(AVATAR_BORDER * (avatarSize / BASE_AVATAR_SIZE)));
1868
+ const avatarBorderColor = layout.avatarBorderColor ? parseHex(layout.avatarBorderColor) : layout.accentColor;
1869
+ ctx.save();
1870
+ ctx.beginPath();
1871
+ ctx.roundRect(0, 0, width, height, [CORNER_RADIUS2]);
1872
+ ctx.clip();
1873
+ ctx.fillStyle = "#111318";
1874
+ ctx.fillRect(0, 0, width, height);
1875
+ const bannerImage = layout.customBackground ? await (0, import_canvas15.loadImage)(layout.customBackground).catch(() => void 0) : void 0;
1876
+ if (bannerImage) {
1877
+ drawCoverImage(ctx, bannerImage, 0, 0, width, height);
1878
+ const overlay = ctx.createLinearGradient(0, 0, 0, height);
1879
+ overlay.addColorStop(0, "rgba(8, 9, 12, 0.1)");
1880
+ overlay.addColorStop(0.3, "rgba(8, 9, 12, 0.3)");
1881
+ overlay.addColorStop(0.55, "rgba(13, 15, 20, 0.55)");
1882
+ overlay.addColorStop(1, "rgba(13, 15, 20, 0.9)");
1883
+ ctx.fillStyle = overlay;
1884
+ ctx.fillRect(0, 0, width, height);
1885
+ } else {
1886
+ const grd = ctx.createLinearGradient(0, 0, width, BANNER_HEIGHT);
1887
+ grd.addColorStop(0, hexToRgba(layout.accentColor, 0.85));
1888
+ grd.addColorStop(1, hexToRgba(layout.accentColor, 0.3));
1889
+ ctx.fillStyle = grd;
1890
+ ctx.fillRect(0, 0, width, BANNER_HEIGHT);
1891
+ }
1892
+ if (layout.serverTag) {
1893
+ await drawServerTagPill(ctx, layout.serverTag);
1894
+ }
1895
+ if (layout.badges?.length) {
1896
+ await drawBadgesPill(ctx, width, layout.badges, layout.maxBadges ?? 3);
1897
+ }
1898
+ const avatarCx = width / 2;
1899
+ const avatarCy = BANNER_HEIGHT;
1900
+ const outerRadius = avatarSize / 2 + avatarBorder;
1901
+ ctx.beginPath();
1902
+ ctx.arc(avatarCx, avatarCy, outerRadius, 0, Math.PI * 2);
1903
+ ctx.fillStyle = "#111318";
1904
+ ctx.fill();
1905
+ ctx.beginPath();
1906
+ ctx.arc(avatarCx, avatarCy, outerRadius - avatarBorder / 2, 0, Math.PI * 2);
1907
+ ctx.strokeStyle = avatarBorderColor;
1908
+ ctx.lineWidth = avatarBorder;
1909
+ ctx.stroke();
1910
+ ctx.beginPath();
1911
+ ctx.arc(avatarCx, avatarCy, avatarSize / 2, 0, Math.PI * 2);
1912
+ ctx.fillStyle = "#292b2f";
1913
+ ctx.fill();
1914
+ const avatarImage = await (0, import_canvas15.loadImage)(avatarUrl).catch(() => void 0);
1915
+ if (avatarImage) {
1916
+ ctx.save();
1917
+ ctx.beginPath();
1918
+ ctx.arc(avatarCx, avatarCy, avatarSize / 2, 0, Math.PI * 2);
1919
+ ctx.clip();
1920
+ ctx.drawImage(
1921
+ avatarImage,
1922
+ avatarCx - avatarSize / 2,
1923
+ avatarCy - avatarSize / 2,
1924
+ avatarSize,
1925
+ avatarSize
1926
+ );
1927
+ ctx.restore();
1928
+ }
1929
+ const avatarFrameImage = layout.avatarFrameUrl ? await (0, import_canvas15.loadImage)(layout.avatarFrameUrl).catch(() => void 0) : void 0;
1930
+ if (avatarFrameImage) {
1931
+ const frameSize = avatarSize * 1.2;
1932
+ ctx.drawImage(
1933
+ avatarFrameImage,
1934
+ avatarCx - frameSize / 2,
1935
+ avatarCy - frameSize / 2,
1936
+ frameSize,
1937
+ frameSize
1938
+ );
1939
+ }
1940
+ let cursorY = BANNER_HEIGHT + avatarSize / 2 + 44 * fontScale;
1941
+ const glowColor = layout.glowColor ? parseHex(layout.glowColor) : layout.accentColor;
1942
+ ctx.textAlign = "center";
1943
+ applyTextEffect(ctx, layout.usernameEffect, glowColor);
1944
+ ctx.font = withFallback(`${Math.round(30 * fontScale)}px Helvetica Bold`);
1945
+ ctx.fillStyle = layout.usernameColor ? parseHex(layout.usernameColor) : "#FFFFFF";
1946
+ ctx.fillText(truncateText(username, 24), width / 2, cursorY);
1947
+ if (layout.message) {
1948
+ cursorY += 32 * fontScale;
1949
+ applyTextEffect(ctx, layout.messageEffect, glowColor);
1950
+ ctx.font = withFallback(`${Math.round(18 * fontScale)}px Helvetica`);
1951
+ ctx.fillStyle = layout.messageColor ? parseHex(layout.messageColor) : "rgba(255, 255, 255, 0.85)";
1952
+ ctx.fillText(truncateText(layout.message, 64), width / 2, cursorY);
1953
+ }
1954
+ applyTextEffect(ctx, "none", glowColor);
1955
+ if (layout.memberCount != null) {
1956
+ cursorY += 30 * fontScale;
1957
+ ctx.font = withFallback(`bold ${Math.round(16 * fontScale)}px Helvetica Bold`);
1958
+ ctx.fillStyle = hexToRgba(layout.accentColor, 1);
1959
+ ctx.fillText(`Miembro #${layout.memberCount}`, width / 2, cursorY);
1960
+ }
1961
+ if (layout.dateText) {
1962
+ cursorY += 26 * fontScale;
1963
+ ctx.font = withFallback(`${Math.round(14 * fontScale)}px Helvetica`);
1964
+ ctx.fillStyle = "rgba(255, 255, 255, 0.5)";
1965
+ ctx.fillText(layout.dateText, width / 2, cursorY);
1966
+ }
1967
+ ctx.restore();
1968
+ if (layout.borderColors.length > 0) {
1969
+ drawGradientBorder(ctx, width, height, layout.borderColors, CORNER_RADIUS2);
1970
+ }
1971
+ }
1972
+
1973
+ // Src/Utils/memberEventCard.output.utils.ts
1974
+ async function genMemberEventPng(avatarUrl, username, layout, output) {
1975
+ const { width, height } = getCardDimensions(layout);
1976
+ const { canvas, ctx } = createMemberEventCanvas(width, height);
1977
+ await drawMemberEventCard(ctx, width, height, avatarUrl, username, layout);
1978
+ return encodeCanvas(canvas, output);
1979
+ }
1980
+
1981
+ // Src/Cards/memberEvent.ts
1982
+ var DEFAULT_ACCENT2 = "#2DD4BF";
1983
+ function formatMessage(template, username, guildName, memberCount) {
1984
+ return template.replace(/\{username\}/g, username).replace(/\{user\}/g, username).replace(/\{server\}/g, guildName).replace(/\{memberCount\}/g, memberCount != null ? String(memberCount) : "");
1985
+ }
1986
+ async function renderMemberEventCard(userId, guildName, defaultMessage, options = {}) {
1987
+ if (!userId || typeof userId !== "string") {
1988
+ throw new KiraError("A valid userId is required", "VALIDATION" /* Validation */);
1989
+ }
1990
+ if (!guildName || typeof guildName !== "string") {
1991
+ throw new KiraError("A valid guildName is required", "VALIDATION" /* Validation */);
1992
+ }
1993
+ const data = await fetchUserData(userId, options.guildId, options.bypassCache);
1994
+ const username = data.basicInfo.globalName || data.basicInfo.username;
1995
+ const avatarUrl = data.assets.avatarURL ?? data.assets.defaultAvatarURL;
1996
+ const palette = getThemePalette(options.theme);
1997
+ const accentColor = options.accentColor ? parseHex(options.accentColor) : palette?.accentColor ? parseHex(palette.accentColor) : DEFAULT_ACCENT2;
1998
+ const borderColors = resolveCardColors({
1999
+ custom: options.borderColor,
2000
+ removeBorder: options.removeBorder,
2001
+ useNitroTheme: options.useNitroTheme,
2002
+ nitroColors: data.decoration.profileColors,
2003
+ useRoleColor: options.useRoleColor,
2004
+ roleColor: data.decoration.roleColor,
2005
+ fallback: palette?.borderColor ?? [accentColor]
2006
+ });
2007
+ const rawMessage = options.message ?? defaultMessage;
2008
+ const message = formatMessage(rawMessage, username, guildName, options.memberCount);
2009
+ const dateText = options.showDate ? getDateOrString(options.date, Date.now(), options.localDateType ?? "es") : void 0;
2010
+ const fontScale = options.fontScale && options.fontScale > 0 ? options.fontScale : 1;
2011
+ const avatarFrameUrl = options.showAvatarDecoration ? data.decoration.avatarFrame : null;
2012
+ const serverTag = options.showServerTag ? data.decoration.serverTag : null;
2013
+ const badges = options.showBadges ? data.assets.badges : void 0;
2014
+ const layout = {
2015
+ message,
2016
+ memberCount: options.memberCount,
2017
+ dateText,
2018
+ accentColor,
2019
+ borderColors,
2020
+ usernameColor: options.usernameColor ?? palette?.usernameColor,
2021
+ messageColor: options.messageColor ?? palette?.messageColor,
2022
+ customBackground: options.customBackground,
2023
+ fontScale,
2024
+ avatarFrameUrl,
2025
+ avatarBorderColor: options.avatarBorderColor,
2026
+ serverTag,
2027
+ badges,
2028
+ maxBadges: options.maxBadges,
2029
+ usernameEffect: options.usernameEffect,
2030
+ messageEffect: options.messageEffect,
2031
+ glowColor: options.glowColor ?? palette?.glowColor
2032
+ };
2033
+ try {
2034
+ return await genMemberEventPng(avatarUrl, username, layout, options.output);
2035
+ } catch (error) {
2036
+ if (error instanceof KiraError) throw error;
2037
+ const message2 = error instanceof Error ? error.message : String(error);
2038
+ throw new KiraError(message2, "RENDER" /* Render */);
2039
+ }
2040
+ }
2041
+
2042
+ // Src/Cards/welcomeImage.ts
2043
+ var DEFAULT_WELCOME_MESSAGE = "\xA1Welcome to {server}!";
2044
+ async function welcomeImage(userId, guildName, options = {}) {
2045
+ return renderMemberEventCard(userId, guildName, DEFAULT_WELCOME_MESSAGE, options);
2046
+ }
2047
+
2048
+ // Src/Cards/leaveImage.ts
2049
+ var DEFAULT_LEAVE_MESSAGE = "{username} has left {server}.";
2050
+ async function leaveImage(userId, guildName, options = {}) {
2051
+ return renderMemberEventCard(userId, guildName, DEFAULT_LEAVE_MESSAGE, options);
2052
+ }
2053
+
2054
+ // Src/Utils/LevelUpCard/constants.ts
2055
+ var CARD_WIDTH3 = 700;
2056
+ var CARD_HEIGHT = 260;
2057
+ var CORNER_RADIUS3 = 26;
2058
+ var AVATAR_SIZE = 128;
2059
+ var AVATAR_BORDER2 = 5;
2060
+
2061
+ // Src/Utils/LevelUpCard/dimensions.ts
2062
+ var import_canvas16 = require("@napi-rs/canvas");
2063
+ function getCardDimensions2() {
2064
+ return { width: CARD_WIDTH3, height: CARD_HEIGHT };
2065
+ }
2066
+ function createLevelUpCanvas(width, height) {
2067
+ const canvas = (0, import_canvas16.createCanvas)(width, height);
2068
+ const ctx = canvas.getContext("2d");
2069
+ return { canvas, ctx };
2070
+ }
2071
+
2072
+ // Src/Utils/ShipCard/decorations.ts
2073
+ function drawSparkle(ctx, cx, cy, size, opacity, color) {
2074
+ ctx.save();
2075
+ ctx.translate(cx, cy);
2076
+ ctx.fillStyle = hexToRgba(color, opacity);
2077
+ ctx.beginPath();
2078
+ ctx.moveTo(0, -size);
2079
+ ctx.quadraticCurveTo(size * 0.18, -size * 0.18, size, 0);
2080
+ ctx.quadraticCurveTo(size * 0.18, size * 0.18, 0, size);
2081
+ ctx.quadraticCurveTo(-size * 0.18, size * 0.18, -size, 0);
2082
+ ctx.quadraticCurveTo(-size * 0.18, -size * 0.18, 0, -size);
2083
+ ctx.closePath();
2084
+ ctx.fill();
2085
+ ctx.restore();
2086
+ }
2087
+ function drawSparkles(ctx, width, height, color) {
2088
+ const spots = [
2089
+ [width * 0.31, height * 0.28, 5, 0.55],
2090
+ [width * 0.37, height * 0.68, 3.5, 0.4],
2091
+ [width * 0.62, height * 0.24, 4, 0.45],
2092
+ [width * 0.67, height * 0.7, 6, 0.5],
2093
+ [width * 0.5, height * 0.16, 3, 0.35]
2094
+ ];
2095
+ for (const [x, y, size, opacity] of spots) {
2096
+ drawSparkle(ctx, x, y, size, opacity, color);
2097
+ }
2098
+ }
2099
+ function drawConnector(ctx, fromX, toX, y, color) {
2100
+ ctx.save();
2101
+ ctx.strokeStyle = hexToRgba(color, 0.4);
2102
+ ctx.lineWidth = 2;
2103
+ ctx.setLineDash([1, 7]);
2104
+ ctx.lineCap = "round";
2105
+ ctx.beginPath();
2106
+ ctx.moveTo(fromX, y);
2107
+ ctx.lineTo(toX, y);
2108
+ ctx.stroke();
2109
+ ctx.restore();
2110
+ }
2111
+ function drawShipNamePill(ctx, width, shipName, color) {
2112
+ const safeName = shipName.normalize("NFKD").replace(/[^\p{L}\p{N}\s]/gu, "").trim();
2113
+ if (!safeName) return;
2114
+ ctx.save();
2115
+ ctx.font = withFallback("bold 15px Helvetica Bold");
2116
+ const paddingX = 16;
2117
+ const textWidth = ctx.measureText(safeName).width;
2118
+ const pillWidth = textWidth + paddingX * 2;
2119
+ const pillHeight = 30;
2120
+ const x = width - 24 - pillWidth;
2121
+ const y = 18;
2122
+ ctx.beginPath();
2123
+ ctx.roundRect(x, y, pillWidth, pillHeight, [pillHeight / 2]);
2124
+ const grd = ctx.createLinearGradient(x, y, x + pillWidth, y);
2125
+ grd.addColorStop(0, hexToRgba(color, 0.9));
2126
+ grd.addColorStop(1, hexToRgba(color, 0.55));
2127
+ ctx.fillStyle = grd;
2128
+ ctx.fill();
2129
+ ctx.strokeStyle = "rgba(255, 255, 255, 0.35)";
2130
+ ctx.lineWidth = 1;
2131
+ ctx.stroke();
2132
+ ctx.textAlign = "center";
2133
+ ctx.textBaseline = "middle";
2134
+ ctx.fillStyle = "#FFFFFF";
2135
+ ctx.shadowColor = "rgba(0, 0, 0, 0.35)";
2136
+ ctx.shadowBlur = 4;
2137
+ ctx.fillText(safeName, x + pillWidth / 2, y + pillHeight / 2 + 1);
2138
+ ctx.restore();
2139
+ }
2140
+ function drawVignette(ctx, width, height) {
2141
+ const grd = ctx.createRadialGradient(
2142
+ width / 2,
2143
+ height / 2,
2144
+ height * 0.25,
2145
+ width / 2,
2146
+ height / 2,
2147
+ Math.max(width, height) * 0.75
2148
+ );
2149
+ grd.addColorStop(0, "rgba(0, 0, 0, 0)");
2150
+ grd.addColorStop(1, "rgba(0, 0, 0, 0.45)");
2151
+ ctx.fillStyle = grd;
2152
+ ctx.fillRect(0, 0, width, height);
2153
+ }
2154
+
2155
+ // Src/Utils/LevelUpCard/render.ts
2156
+ async function drawLevelUpCard(ctx, width, height, layout) {
2157
+ const accentColor = parseHex(layout.accentColor);
2158
+ const avatarBorderColor = layout.avatarBorderColor ? parseHex(layout.avatarBorderColor) : accentColor;
2159
+ const kickerColor = layout.kickerColor ? parseHex(layout.kickerColor) : "#FFFFFF";
2160
+ const levelColor = layout.levelColor ? parseHex(layout.levelColor) : "#FFFFFF";
2161
+ const usernameColor = layout.usernameColor ? parseHex(layout.usernameColor) : "#FFFFFF";
2162
+ const xpColor = layout.xpColor ? parseHex(layout.xpColor) : "rgba(255, 255, 255, 0.75)";
2163
+ const barBackgroundColor = layout.barBackgroundColor ? parseHex(layout.barBackgroundColor) : "rgba(0, 0, 0, 0.35)";
2164
+ const backgroundTint = layout.backgroundTint !== false;
2165
+ ctx.save();
2166
+ ctx.beginPath();
2167
+ ctx.roundRect(0, 0, width, height, [CORNER_RADIUS3]);
2168
+ ctx.clip();
2169
+ ctx.fillStyle = "#0c0d11";
2170
+ ctx.fillRect(0, 0, width, height);
2171
+ const backgroundImage = await loadImageSafe(layout.customBackground);
2172
+ if (backgroundImage) {
2173
+ drawCoverImage(ctx, backgroundImage, 0, 0, width, height);
2174
+ ctx.fillStyle = "rgba(8, 9, 13, 0.6)";
2175
+ ctx.fillRect(0, 0, width, height);
2176
+ if (backgroundTint) {
2177
+ const duotone = ctx.createLinearGradient(0, 0, width, height);
2178
+ duotone.addColorStop(0, hexToRgba(accentColor, 0.35));
2179
+ duotone.addColorStop(1, "rgba(8, 9, 13, 0.45)");
2180
+ ctx.fillStyle = duotone;
2181
+ ctx.fillRect(0, 0, width, height);
2182
+ }
2183
+ } else if (backgroundTint) {
2184
+ const grd = ctx.createLinearGradient(0, 0, width, height);
2185
+ grd.addColorStop(0, hexToRgba(accentColor, 0.38));
2186
+ grd.addColorStop(0.55, "rgba(18, 15, 24, 1)");
2187
+ grd.addColorStop(1, "rgba(10, 11, 15, 1)");
2188
+ ctx.fillStyle = grd;
2189
+ ctx.fillRect(0, 0, width, height);
2190
+ const bgGlow = ctx.createRadialGradient(
2191
+ width * 0.18,
2192
+ height / 2,
2193
+ 10,
2194
+ width * 0.18,
2195
+ height / 2,
2196
+ width * 0.45
2197
+ );
2198
+ bgGlow.addColorStop(0, hexToRgba(accentColor, 0.4));
2199
+ bgGlow.addColorStop(1, "rgba(0, 0, 0, 0)");
2200
+ ctx.fillStyle = bgGlow;
2201
+ ctx.fillRect(0, 0, width, height);
2202
+ } else {
2203
+ const grd = ctx.createLinearGradient(0, 0, width, height);
2204
+ grd.addColorStop(0, "rgba(30, 30, 34, 1)");
2205
+ grd.addColorStop(1, "rgba(10, 11, 15, 1)");
2206
+ ctx.fillStyle = grd;
2207
+ ctx.fillRect(0, 0, width, height);
2208
+ }
2209
+ drawSparkles(ctx, width, height, accentColor);
2210
+ if (layout.badges?.length) {
2211
+ await drawBadgesPill(ctx, width, layout.badges, layout.maxBadges ?? 3, 30, 46);
2212
+ }
2213
+ const hasMessage = Boolean(layout.message);
2214
+ const hasBar = layout.currentXp != null && layout.requiredXp != null && layout.requiredXp > 0;
2215
+ const avatarCx = 104;
2216
+ const avatarCy = height / 2;
2217
+ const outerRadius = AVATAR_SIZE / 2 + AVATAR_BORDER2;
2218
+ if (backgroundTint) {
2219
+ const avatarGlow = ctx.createRadialGradient(
2220
+ avatarCx,
2221
+ avatarCy,
2222
+ outerRadius * 0.6,
2223
+ avatarCx,
2224
+ avatarCy,
2225
+ outerRadius * 1.8
2226
+ );
2227
+ avatarGlow.addColorStop(0, hexToRgba(avatarBorderColor, 0.35));
2228
+ avatarGlow.addColorStop(1, "rgba(0, 0, 0, 0)");
2229
+ ctx.fillStyle = avatarGlow;
2230
+ ctx.beginPath();
2231
+ ctx.arc(avatarCx, avatarCy, outerRadius * 1.8, 0, Math.PI * 2);
2232
+ ctx.fill();
2233
+ }
2234
+ ctx.beginPath();
2235
+ ctx.arc(avatarCx, avatarCy, outerRadius, 0, Math.PI * 2);
2236
+ ctx.fillStyle = "#111318";
2237
+ ctx.fill();
2238
+ ctx.beginPath();
2239
+ ctx.arc(avatarCx, avatarCy, outerRadius - AVATAR_BORDER2 / 2, 0, Math.PI * 2);
2240
+ ctx.strokeStyle = avatarBorderColor;
2241
+ ctx.lineWidth = AVATAR_BORDER2;
2242
+ ctx.stroke();
2243
+ ctx.beginPath();
2244
+ ctx.arc(avatarCx, avatarCy, AVATAR_SIZE / 2, 0, Math.PI * 2);
2245
+ ctx.fillStyle = "#292b2f";
2246
+ ctx.fill();
2247
+ const avatarImage = await loadImageSafe(layout.avatarUrl);
2248
+ if (avatarImage) {
2249
+ ctx.save();
2250
+ ctx.beginPath();
2251
+ ctx.arc(avatarCx, avatarCy, AVATAR_SIZE / 2, 0, Math.PI * 2);
2252
+ ctx.clip();
2253
+ ctx.drawImage(
2254
+ avatarImage,
2255
+ avatarCx - AVATAR_SIZE / 2,
2256
+ avatarCy - AVATAR_SIZE / 2,
2257
+ AVATAR_SIZE,
2258
+ AVATAR_SIZE
2259
+ );
2260
+ ctx.restore();
2261
+ }
2262
+ const avatarFrameImage = await loadImageSafe(layout.avatarFrameUrl ?? void 0);
2263
+ if (avatarFrameImage) {
2264
+ const frameSize = AVATAR_SIZE * 1.2;
2265
+ ctx.drawImage(
2266
+ avatarFrameImage,
2267
+ avatarCx - frameSize / 2,
2268
+ avatarCy - frameSize / 2,
2269
+ frameSize,
2270
+ frameSize
2271
+ );
2272
+ }
2273
+ const contentX = 196;
2274
+ const contentWidth = width - contentX - 40;
2275
+ const rows = [
2276
+ { kind: "kicker", height: 16, gapBefore: 0 },
2277
+ { kind: "username", height: 38, gapBefore: 10 },
2278
+ { kind: "pill", height: 30, gapBefore: 10 }
2279
+ ];
2280
+ if (hasMessage) rows.push({ kind: "message", height: 18, gapBefore: 14 });
2281
+ if (hasBar) rows.push({ kind: "bar", height: 16, gapBefore: hasMessage ? 20 : 24 });
2282
+ const totalHeight = rows.reduce((sum, row) => sum + row.gapBefore + row.height, 0);
2283
+ let rowTop = avatarCy - totalHeight / 2;
2284
+ ctx.textAlign = "left";
2285
+ for (const row of rows) {
2286
+ rowTop += row.gapBefore;
2287
+ const centerY = rowTop + row.height / 2;
2288
+ if (row.kind === "kicker") {
2289
+ ctx.font = withFallback("bold 14px Helvetica Bold");
2290
+ ctx.fillStyle = hexToRgba(kickerColor, 1);
2291
+ ctx.save();
2292
+ ctx.textBaseline = "middle";
2293
+ ctx.fillText("LEVELED UP", contentX, centerY);
2294
+ ctx.restore();
2295
+ } else if (row.kind === "username") {
2296
+ ctx.font = withFallback("bold 34px Helvetica Bold");
2297
+ ctx.fillStyle = usernameColor;
2298
+ ctx.save();
2299
+ ctx.textBaseline = "middle";
2300
+ ctx.fillText(truncateText(layout.username, 22), contentX, centerY, contentWidth);
2301
+ ctx.restore();
2302
+ } else if (row.kind === "pill") {
2303
+ const levelPillText = `LEVEL ${layout.level}`;
2304
+ ctx.font = withFallback("bold 16px Helvetica Bold");
2305
+ const levelPillTextWidth = ctx.measureText(levelPillText).width;
2306
+ const levelPillPaddingX = 16;
2307
+ const levelPillWidth = levelPillTextWidth + levelPillPaddingX * 2;
2308
+ const pillFill = ctx.createLinearGradient(contentX, rowTop, contentX, rowTop + row.height);
2309
+ pillFill.addColorStop(0, hexToRgba(levelColor, 0.24));
2310
+ pillFill.addColorStop(1, hexToRgba(levelColor, 0.12));
2311
+ ctx.fillStyle = pillFill;
2312
+ ctx.beginPath();
2313
+ ctx.roundRect(contentX, rowTop, levelPillWidth, row.height, [row.height / 2]);
2314
+ ctx.fill();
2315
+ ctx.strokeStyle = hexToRgba(levelColor, 0.8);
2316
+ ctx.lineWidth = 1.5;
2317
+ ctx.beginPath();
2318
+ ctx.roundRect(contentX, rowTop, levelPillWidth, row.height, [row.height / 2]);
2319
+ ctx.stroke();
2320
+ ctx.save();
2321
+ ctx.textBaseline = "middle";
2322
+ ctx.fillStyle = levelColor;
2323
+ ctx.fillText(levelPillText, contentX + levelPillPaddingX, centerY);
2324
+ ctx.restore();
2325
+ } else if (row.kind === "message") {
2326
+ ctx.font = withFallback("15px Helvetica");
2327
+ ctx.fillStyle = layout.messageColor ? parseHex(layout.messageColor) : "rgba(255, 255, 255, 0.65)";
2328
+ ctx.save();
2329
+ ctx.textBaseline = "middle";
2330
+ ctx.fillText(truncateText(layout.message, 58), contentX, centerY, contentWidth);
2331
+ ctx.restore();
2332
+ } else if (row.kind === "bar") {
2333
+ const barX = contentX;
2334
+ const barWidth = contentWidth;
2335
+ const barHeight = row.height;
2336
+ ctx.font = withFallback("bold 12px Helvetica");
2337
+ ctx.textAlign = "right";
2338
+ ctx.fillStyle = xpColor;
2339
+ ctx.fillText(
2340
+ `${abbreviateNumber(layout.currentXp)} / ${abbreviateNumber(layout.requiredXp)} XP`,
2341
+ barX + barWidth,
2342
+ rowTop - 8
2343
+ );
2344
+ ctx.textAlign = "left";
2345
+ ctx.fillStyle = barBackgroundColor;
2346
+ ctx.beginPath();
2347
+ ctx.roundRect(barX, rowTop, barWidth, barHeight, [barHeight / 2]);
2348
+ ctx.fill();
2349
+ const progress = Math.min(1, Math.max(0, layout.currentXp / layout.requiredXp));
2350
+ const minVisibleWidth = Math.min(barWidth, barHeight * 1.5);
2351
+ const filledWidth = progress > 0 ? Math.max(minVisibleWidth, Math.round(barWidth * progress)) : 0;
2352
+ if (filledWidth > 0) {
2353
+ const barGrd = ctx.createLinearGradient(barX, 0, barX + filledWidth, 0);
2354
+ for (let i = 0; i < layout.barColors.length; i++) {
2355
+ const stop = layout.barColors.length === 1 ? 0 : i / (layout.barColors.length - 1);
2356
+ barGrd.addColorStop(stop, layout.barColors[i]);
2357
+ }
2358
+ ctx.save();
2359
+ ctx.shadowColor = hexToRgba(layout.barColors[layout.barColors.length - 1], 0.85);
2360
+ ctx.shadowBlur = 12;
2361
+ ctx.fillStyle = barGrd;
2362
+ ctx.beginPath();
2363
+ ctx.roundRect(barX, rowTop, filledWidth, barHeight, [barHeight / 2]);
2364
+ ctx.fill();
2365
+ ctx.shadowBlur = 0;
2366
+ ctx.fillStyle = "rgba(255, 255, 255, 0.35)";
2367
+ ctx.beginPath();
2368
+ ctx.roundRect(barX + 3, rowTop + 2, Math.max(0, filledWidth - 6), barHeight * 0.32, [
2369
+ barHeight / 2
2370
+ ]);
2371
+ ctx.fill();
2372
+ ctx.restore();
2373
+ }
2374
+ }
2375
+ rowTop += row.height;
2376
+ }
2377
+ ctx.restore();
2378
+ if (layout.borderColors.length > 0) {
2379
+ drawGradientBorder(ctx, width, height, layout.borderColors, CORNER_RADIUS3);
2380
+ }
2381
+ }
2382
+
2383
+ // Src/Utils/levelUpCard.output.utils.ts
2384
+ async function genLevelUpPng(layout, output) {
2385
+ const { width, height } = getCardDimensions2();
2386
+ const { canvas, ctx } = createLevelUpCanvas(width, height);
2387
+ await drawLevelUpCard(ctx, width, height, layout);
2388
+ return encodeCanvas(canvas, output);
2389
+ }
2390
+
2391
+ // Src/Cards/levelUpImage.ts
2392
+ var DEFAULT_ACCENT3 = "#FACC15";
2393
+ async function levelUpImage(userId, level, options = {}) {
2394
+ if (!userId || typeof userId !== "string") {
2395
+ throw new KiraError("A valid userId is required", "VALIDATION" /* Validation */);
2396
+ }
2397
+ if (typeof level !== "number" || isNaN(level)) {
2398
+ throw new KiraError("A valid level is required", "VALIDATION" /* Validation */);
2399
+ }
2400
+ const data = await fetchUserData(userId, options.guildId, options.bypassCache);
2401
+ const username = data.basicInfo.globalName || data.basicInfo.username;
2402
+ const avatarUrl = data.assets.avatarURL ?? data.assets.defaultAvatarURL;
2403
+ const palette = getThemePalette(options.theme);
2404
+ const accentColor = options.accentColor ? parseHex(options.accentColor) : palette?.accentColor ? parseHex(palette.accentColor) : DEFAULT_ACCENT3;
2405
+ const borderColors = resolveCardColors({
2406
+ custom: options.borderColor,
2407
+ removeBorder: options.removeBorder,
2408
+ useNitroTheme: options.useNitroTheme,
2409
+ nitroColors: data.decoration.profileColors,
2410
+ useRoleColor: options.useRoleColor,
2411
+ roleColor: data.decoration.roleColor,
2412
+ fallback: palette?.borderColor ?? [accentColor]
2413
+ });
2414
+ const barColors = resolveCardColors({
2415
+ custom: options.barColor,
2416
+ fallback: palette?.barColor ?? [accentColor]
2417
+ });
2418
+ const showAvatarDecoration = options.showAvatarDecoration !== false;
2419
+ const avatarFrameUrl = showAvatarDecoration ? data.decoration.avatarFrame : null;
2420
+ const badges = options.showBadges ? data.assets.badges : void 0;
2421
+ const layout = {
2422
+ username,
2423
+ avatarUrl,
2424
+ level,
2425
+ currentXp: options.currentXp,
2426
+ requiredXp: options.requiredXp,
2427
+ message: options.message,
2428
+ accentColor,
2429
+ borderColors,
2430
+ barColors,
2431
+ barBackgroundColor: options.barBackgroundColor,
2432
+ levelColor: options.levelColor ?? palette?.levelColor,
2433
+ usernameColor: options.usernameColor ?? palette?.usernameColor,
2434
+ messageColor: options.messageColor ?? palette?.messageColor,
2435
+ kickerColor: options.kickerColor,
2436
+ xpColor: options.xpColor,
2437
+ customBackground: options.customBackground,
2438
+ backgroundTint: options.backgroundTint,
2439
+ avatarBorderColor: options.avatarBorderColor,
2440
+ avatarFrameUrl,
2441
+ badges,
2442
+ maxBadges: options.maxBadges
2443
+ };
2444
+ try {
2445
+ return await genLevelUpPng(layout, options.output);
2446
+ } catch (error) {
2447
+ if (error instanceof KiraError) throw error;
2448
+ const message = error instanceof Error ? error.message : String(error);
2449
+ throw new KiraError(message, "RENDER" /* Render */);
2450
+ }
2451
+ }
2452
+
2453
+ // Src/Utils/achievementCard.utils.ts
2454
+ var import_canvas17 = require("@napi-rs/canvas");
2455
+ var CARD_WIDTH4 = 700;
2456
+ var CARD_HEIGHT2 = 220;
2457
+ var CORNER_RADIUS4 = 24;
2458
+ var ICON_SIZE = 96;
2459
+ var ICON_MARGIN = 32;
2460
+ var RARITY_COLORS = {
2461
+ common: "#9AA3AF",
2462
+ rare: "#3B82F6",
2463
+ epic: "#A855F7",
2464
+ legendary: "#F59E0B"
2465
+ };
2466
+ var RARITY_LABELS = {
2467
+ common: "Common",
2468
+ rare: "Queer",
2469
+ epic: "Epic",
2470
+ legendary: "Legendary"
2471
+ };
2472
+ function resolveAccentColor(layout) {
2473
+ if (layout.accentColor) return parseHex(layout.accentColor);
2474
+ const rarity = layout.rarity ?? "common";
2475
+ return RARITY_COLORS[rarity];
2476
+ }
2477
+ function getCardDimensions3() {
2478
+ return { width: CARD_WIDTH4, height: CARD_HEIGHT2 };
2479
+ }
2480
+ function createAchievementCanvas(width, height) {
2481
+ const canvas = (0, import_canvas17.createCanvas)(width, height);
2482
+ const ctx = canvas.getContext("2d");
2483
+ return { canvas, ctx };
2484
+ }
2485
+ async function drawAchievementCard(ctx, width, height, layout) {
2486
+ const accentColor = resolveAccentColor(layout);
2487
+ const borderColors = layout.noBorder ? [] : layout.borderColors?.length ? layout.borderColors : [accentColor];
2488
+ ctx.save();
2489
+ ctx.beginPath();
2490
+ ctx.roundRect(0, 0, width, height, [CORNER_RADIUS4]);
2491
+ ctx.clip();
2492
+ ctx.fillStyle = "#111318";
2493
+ ctx.fillRect(0, 0, width, height);
2494
+ const backgroundImage = layout.customBackground ? await (0, import_canvas17.loadImage)(layout.customBackground).catch(() => void 0) : void 0;
2495
+ if (backgroundImage) {
2496
+ drawCoverImage(ctx, backgroundImage, 0, 0, width, height);
2497
+ const overlay = ctx.createLinearGradient(0, 0, width, 0);
2498
+ overlay.addColorStop(0, "rgba(10, 11, 15, 0.9)");
2499
+ overlay.addColorStop(1, "rgba(10, 11, 15, 0.55)");
2500
+ ctx.fillStyle = overlay;
2501
+ ctx.fillRect(0, 0, width, height);
2502
+ } else {
2503
+ const grd = ctx.createLinearGradient(0, 0, width, height);
2504
+ grd.addColorStop(0, hexToRgba(accentColor, 0.22));
2505
+ grd.addColorStop(1, "rgba(17, 19, 24, 1)");
2506
+ ctx.fillStyle = grd;
2507
+ ctx.fillRect(0, 0, width, height);
2508
+ }
2509
+ const iconCx = ICON_MARGIN + ICON_SIZE / 2;
2510
+ const iconCy = height / 2;
2511
+ ctx.beginPath();
2512
+ ctx.arc(iconCx, iconCy, ICON_SIZE / 2 + 6, 0, Math.PI * 2);
2513
+ ctx.fillStyle = hexToRgba(accentColor, 0.18);
2514
+ ctx.fill();
2515
+ ctx.beginPath();
2516
+ ctx.arc(iconCx, iconCy, ICON_SIZE / 2, 0, Math.PI * 2);
2517
+ ctx.strokeStyle = accentColor;
2518
+ ctx.lineWidth = 4;
2519
+ ctx.stroke();
2520
+ const iconImage = layout.iconUrl ? await (0, import_canvas17.loadImage)(layout.iconUrl).catch(() => void 0) : void 0;
2521
+ if (iconImage) {
2522
+ ctx.save();
2523
+ ctx.beginPath();
2524
+ ctx.arc(iconCx, iconCy, ICON_SIZE / 2 - 6, 0, Math.PI * 2);
2525
+ ctx.clip();
2526
+ ctx.drawImage(
2527
+ iconImage,
2528
+ iconCx - ICON_SIZE / 2 + 6,
2529
+ iconCy - ICON_SIZE / 2 + 6,
2530
+ ICON_SIZE - 12,
2531
+ ICON_SIZE - 12
2532
+ );
2533
+ ctx.restore();
2534
+ } else {
2535
+ ctx.font = withFallback(`${Math.round(ICON_SIZE * 0.45)}px Helvetica Bold`);
2536
+ ctx.textAlign = "center";
2537
+ ctx.fillStyle = accentColor;
2538
+ ctx.fillText("\u2605", iconCx, iconCy + ICON_SIZE * 0.16);
2539
+ }
2540
+ const textX = ICON_MARGIN * 2 + ICON_SIZE;
2541
+ let cursorY = height / 2 - 30;
2542
+ ctx.textAlign = "left";
2543
+ if (layout.usernameLine) {
2544
+ ctx.font = withFallback("14px Helvetica");
2545
+ ctx.fillStyle = "rgba(255, 255, 255, 0.55)";
2546
+ ctx.fillText(truncateText(layout.usernameLine, 40), textX, cursorY);
2547
+ cursorY += 26;
2548
+ }
2549
+ const rarity = layout.rarity ?? "common";
2550
+ ctx.font = withFallback("12px Helvetica Bold");
2551
+ const rarityLabel = RARITY_LABELS[rarity].toUpperCase();
2552
+ const rarityWidth = ctx.measureText(rarityLabel).width;
2553
+ const rarityPadding = 8;
2554
+ const rarityHeight = 20;
2555
+ ctx.beginPath();
2556
+ ctx.roundRect(textX, cursorY - rarityHeight + 4, rarityWidth + rarityPadding * 2, rarityHeight, [
2557
+ rarityHeight / 2
2558
+ ]);
2559
+ ctx.fillStyle = hexToRgba(accentColor, 0.25);
2560
+ ctx.fill();
2561
+ ctx.fillStyle = accentColor;
2562
+ ctx.fillText(rarityLabel, textX + rarityPadding, cursorY - 6);
2563
+ cursorY += 28;
2564
+ ctx.font = withFallback("26px Helvetica Bold");
2565
+ ctx.fillStyle = "#FFFFFF";
2566
+ ctx.fillText(truncateText(layout.title, 34), textX, cursorY);
2567
+ cursorY += 30;
2568
+ if (layout.description) {
2569
+ ctx.font = withFallback("15px Helvetica");
2570
+ ctx.fillStyle = "rgba(255, 255, 255, 0.75)";
2571
+ ctx.fillText(truncateText(layout.description, 60), textX, cursorY);
2572
+ cursorY += 24;
2573
+ }
2574
+ if (layout.progressText) {
2575
+ ctx.font = withFallback("13px Helvetica");
2576
+ ctx.fillStyle = hexToRgba(accentColor, 1);
2577
+ ctx.fillText(layout.progressText, textX, cursorY);
2578
+ }
2579
+ ctx.restore();
2580
+ if (borderColors.length > 0) {
2581
+ drawGradientBorder(ctx, width, height, borderColors, CORNER_RADIUS4);
2582
+ }
2583
+ }
2584
+
2585
+ // Src/Utils/achievementCard.output.utils.ts
2586
+ async function genAchievementPng(layout, output) {
2587
+ const { width, height } = getCardDimensions3();
2588
+ const { canvas, ctx } = createAchievementCanvas(width, height);
2589
+ await drawAchievementCard(ctx, width, height, layout);
2590
+ return encodeCanvas(canvas, output);
2591
+ }
2592
+
2593
+ // Src/Cards/achievementImage.ts
2594
+ async function achievementImage(userId, title, options = {}) {
2595
+ if (!userId || typeof userId !== "string") {
2596
+ throw new KiraError("A valid userId is required", "VALIDATION" /* Validation */);
2597
+ }
2598
+ if (!title || typeof title !== "string") {
2599
+ throw new KiraError("A valid title is required", "VALIDATION" /* Validation */);
2600
+ }
2601
+ const data = await fetchUserData(userId, options.guildId, options.bypassCache);
2602
+ const username = data.basicInfo.globalName || data.basicInfo.username;
2603
+ const palette = getThemePalette(options.theme);
2604
+ const accentColor = options.accentColor ?? palette?.accentColor;
2605
+ const borderColors = resolveCardColors({
2606
+ custom: options.borderColor,
2607
+ removeBorder: options.removeBorder,
2608
+ useNitroTheme: options.useNitroTheme,
2609
+ nitroColors: data.decoration.profileColors,
2610
+ useRoleColor: options.useRoleColor,
2611
+ roleColor: data.decoration.roleColor,
2612
+ fallback: palette?.borderColor
2613
+ });
2614
+ const layout = {
2615
+ title,
2616
+ description: options.description,
2617
+ iconUrl: options.iconUrl,
2618
+ rarity: options.rarity,
2619
+ accentColor,
2620
+ borderColors: borderColors.length ? borderColors : void 0,
2621
+ noBorder: options.removeBorder,
2622
+ customBackground: options.customBackground,
2623
+ usernameLine: options.showUsername === false ? void 0 : username,
2624
+ progressText: options.progressText
2625
+ };
2626
+ try {
2627
+ return await genAchievementPng(layout, options.output);
2628
+ } catch (error) {
2629
+ if (error instanceof KiraError) throw error;
2630
+ const message = error instanceof Error ? error.message : String(error);
2631
+ throw new KiraError(message, "RENDER" /* Render */);
2632
+ }
2633
+ }
2634
+
2635
+ // Src/Utils/ShipCard/constants.ts
2636
+ var CARD_WIDTH5 = 700;
2637
+ var CARD_HEIGHT3 = 260;
2638
+ var CORNER_RADIUS5 = 26;
2639
+ var AVATAR_SIZE2 = 150;
2640
+ var AVATAR_BORDER3 = 6;
2641
+ var HEART_WIDTH = 140;
2642
+ var HEART_HEIGHT = 150;
2643
+ var DEFAULT_ACCENT4 = "#EC4899";
2644
+ var MESSAGE_POOL = [
2645
+ {
2646
+ min: 90,
2647
+ messages: [
2648
+ "Definitely the cutest couple.",
2649
+ "A perfect match\u2014this is true love.",
2650
+ "Soulmates confirmed."
2651
+ ]
2652
+ },
2653
+ {
2654
+ min: 70,
2655
+ messages: [
2656
+ "There's great chemistry here.",
2657
+ "This looks very promising.",
2658
+ "A strong connection is forming."
2659
+ ]
2660
+ },
2661
+ {
2662
+ min: 40,
2663
+ messages: [
2664
+ "It could work with a little effort.",
2665
+ "It's a close call\u2014anything could happen.",
2666
+ "Not amazing, but there's potential."
2667
+ ]
2668
+ },
2669
+ {
2670
+ min: 0,
2671
+ messages: ["Better off staying friends.", "This needs a lot of work.", "Fate had other plans."]
2672
+ }
2673
+ ];
2674
+
2675
+ // Src/Utils/ShipCard/compatibility.ts
2676
+ function hashPair(a, b) {
2677
+ const combined = [a, b].sort().join(":");
2678
+ let hash = 5381;
2679
+ for (let i = 0; i < combined.length; i++) {
2680
+ hash = hash * 33 ^ combined.charCodeAt(i);
2681
+ }
2682
+ return Math.abs(hash);
2683
+ }
2684
+ function computeCompatibility(leftId, rightId) {
2685
+ return hashPair(leftId, rightId) % 101;
2686
+ }
2687
+ function pickShipMessage(leftId, rightId, percentage) {
2688
+ const bucket = MESSAGE_POOL.find((entry) => percentage >= entry.min) ?? MESSAGE_POOL[MESSAGE_POOL.length - 1];
2689
+ const index = hashPair(leftId, rightId) % bucket.messages.length;
2690
+ return bucket.messages[index];
2691
+ }
2692
+
2693
+ // Src/Utils/ShipCard/canvasSetup.ts
2694
+ var import_canvas18 = require("@napi-rs/canvas");
2695
+ function getCardDimensions4() {
2696
+ return { width: CARD_WIDTH5, height: CARD_HEIGHT3 };
2697
+ }
2698
+ function createShipCanvas(width, height) {
2699
+ const canvas = (0, import_canvas18.createCanvas)(width, height);
2700
+ const ctx = canvas.getContext("2d");
2701
+ return { canvas, ctx };
2702
+ }
2703
+
2704
+ // Src/Utils/ShipCard/heartMeter.ts
2705
+ function traceHeartPath(ctx, cx, topY, width, height) {
2706
+ const halfW = width / 2;
2707
+ const lobeHeight = height * 0.3;
2708
+ const midY = topY + (height + lobeHeight) / 2;
2709
+ const bottomY = topY + height;
2710
+ ctx.moveTo(cx, topY + lobeHeight);
2711
+ ctx.bezierCurveTo(cx, topY, cx - halfW, topY, cx - halfW, topY + lobeHeight);
2712
+ ctx.bezierCurveTo(cx - halfW, midY, cx, midY, cx, bottomY);
2713
+ ctx.bezierCurveTo(cx, midY, cx + halfW, midY, cx + halfW, topY + lobeHeight);
2714
+ ctx.bezierCurveTo(cx + halfW, topY, cx, topY, cx, topY + lobeHeight);
2715
+ }
2716
+ function drawHeartIcon(ctx, cx, cy, size, color) {
2717
+ ctx.save();
2718
+ ctx.beginPath();
2719
+ traceHeartPath(ctx, cx, cy - size / 2, size, size);
2720
+ ctx.closePath();
2721
+ ctx.fillStyle = color;
2722
+ ctx.fill();
2723
+ ctx.restore();
2724
+ }
2725
+ function drawHeartMeter(ctx, cx, cy, width, height, percentage, fillColor) {
2726
+ const topY = cy - height / 2;
2727
+ const bottomY = cy + height / 2;
2728
+ ctx.save();
2729
+ ctx.shadowColor = hexToRgba(fillColor, 0.55);
2730
+ ctx.shadowBlur = 22;
2731
+ ctx.beginPath();
2732
+ traceHeartPath(ctx, cx, topY, width, height);
2733
+ ctx.fillStyle = "rgba(8, 9, 13, 0.55)";
2734
+ ctx.fill();
2735
+ ctx.restore();
2736
+ ctx.save();
2737
+ ctx.beginPath();
2738
+ traceHeartPath(ctx, cx, topY, width, height);
2739
+ ctx.clip();
2740
+ ctx.fillStyle = "rgba(255, 255, 255, 0.06)";
2741
+ ctx.fillRect(cx - width, topY, width * 2, height);
2742
+ const fillHeight = height * (percentage / 100);
2743
+ const startY = bottomY - fillHeight;
2744
+ ctx.beginPath();
2745
+ ctx.moveTo(cx - width, bottomY + 4);
2746
+ ctx.lineTo(cx - width, startY);
2747
+ for (let x = -width; x <= width; x += 6) {
2748
+ const waveY = startY + Math.sin((x + cx) * 0.08) * 4;
2749
+ ctx.lineTo(cx + x, waveY);
2750
+ }
2751
+ ctx.lineTo(cx + width, bottomY + 4);
2752
+ ctx.closePath();
2753
+ const fillGrd = ctx.createLinearGradient(0, startY, 0, bottomY);
2754
+ fillGrd.addColorStop(0, hexToRgba(fillColor, 0.95));
2755
+ fillGrd.addColorStop(1, hexToRgba(fillColor, 0.75));
2756
+ ctx.fillStyle = fillGrd;
2757
+ ctx.fill();
2758
+ ctx.fillStyle = "rgba(255, 255, 255, 0.18)";
2759
+ ctx.fillRect(cx - width, startY, width * 2, Math.max(4, fillHeight * 0.12));
2760
+ ctx.restore();
2761
+ ctx.save();
2762
+ ctx.beginPath();
2763
+ traceHeartPath(ctx, cx, topY, width, height);
2764
+ ctx.clip();
2765
+ const shineGrd = ctx.createRadialGradient(
2766
+ cx - width * 0.28,
2767
+ topY + height * 0.32,
2768
+ 2,
2769
+ cx - width * 0.28,
2770
+ topY + height * 0.32,
2771
+ width * 0.6
2772
+ );
2773
+ shineGrd.addColorStop(0, "rgba(255, 255, 255, 0.28)");
2774
+ shineGrd.addColorStop(1, "rgba(255, 255, 255, 0)");
2775
+ ctx.fillStyle = shineGrd;
2776
+ ctx.fillRect(cx - width, topY, width * 2, height);
2777
+ ctx.restore();
2778
+ ctx.save();
2779
+ ctx.beginPath();
2780
+ traceHeartPath(ctx, cx, topY, width, height);
2781
+ ctx.strokeStyle = "rgba(255, 255, 255, 0.9)";
2782
+ ctx.lineWidth = 3.5;
2783
+ ctx.stroke();
2784
+ ctx.restore();
2785
+ ctx.save();
2786
+ ctx.font = withFallback(`bold ${Math.round(height * 0.19)}px Helvetica Bold`);
2787
+ ctx.textAlign = "center";
2788
+ ctx.textBaseline = "middle";
2789
+ ctx.shadowColor = "rgba(0, 0, 0, 0.45)";
2790
+ ctx.shadowBlur = 8;
2791
+ ctx.shadowOffsetY = 2;
2792
+ ctx.fillStyle = "#FFFFFF";
2793
+ ctx.fillText(`${percentage}%`, cx, cy + height * 0.04);
2794
+ ctx.restore();
2795
+ }
2796
+
2797
+ // Src/Utils/ShipCard/avatar.ts
2798
+ async function drawAvatarCircle(ctx, cx, cy, url, accentColor) {
2799
+ const outerRadius = AVATAR_SIZE2 / 2 + AVATAR_BORDER3;
2800
+ ctx.save();
2801
+ ctx.shadowColor = hexToRgba(accentColor, 0.55);
2802
+ ctx.shadowBlur = 26;
2803
+ ctx.beginPath();
2804
+ ctx.arc(cx, cy, outerRadius, 0, Math.PI * 2);
2805
+ ctx.fillStyle = "#0c0d11";
2806
+ ctx.fill();
2807
+ ctx.restore();
2808
+ const ringGrd = ctx.createLinearGradient(cx, cy - outerRadius, cx, cy + outerRadius);
2809
+ ringGrd.addColorStop(0, hexToRgba(accentColor, 1));
2810
+ ringGrd.addColorStop(1, hexToRgba(accentColor, 0.55));
2811
+ ctx.beginPath();
2812
+ ctx.arc(cx, cy, outerRadius - AVATAR_BORDER3 / 2, 0, Math.PI * 2);
2813
+ ctx.strokeStyle = ringGrd;
2814
+ ctx.lineWidth = AVATAR_BORDER3;
2815
+ ctx.stroke();
2816
+ ctx.beginPath();
2817
+ ctx.arc(cx, cy, outerRadius + 2, 0, Math.PI * 2);
2818
+ ctx.strokeStyle = "rgba(255, 255, 255, 0.35)";
2819
+ ctx.lineWidth = 1.5;
2820
+ ctx.stroke();
2821
+ const avatarImage = await loadImageSafe(url);
2822
+ ctx.save();
2823
+ ctx.beginPath();
2824
+ ctx.arc(cx, cy, AVATAR_SIZE2 / 2, 0, Math.PI * 2);
2825
+ ctx.clip();
2826
+ if (avatarImage) {
2827
+ ctx.drawImage(
2828
+ avatarImage,
2829
+ cx - AVATAR_SIZE2 / 2,
2830
+ cy - AVATAR_SIZE2 / 2,
2831
+ AVATAR_SIZE2,
2832
+ AVATAR_SIZE2
2833
+ );
2834
+ } else {
2835
+ ctx.fillStyle = "#2b2d33";
2836
+ ctx.fillRect(cx - AVATAR_SIZE2 / 2, cy - AVATAR_SIZE2 / 2, AVATAR_SIZE2, AVATAR_SIZE2);
2837
+ ctx.font = withFallback(`${Math.round(AVATAR_SIZE2 * 0.4)}px Helvetica Bold`);
2838
+ ctx.textAlign = "center";
2839
+ ctx.textBaseline = "middle";
2840
+ ctx.fillStyle = "rgba(255, 255, 255, 0.7)";
2841
+ ctx.fillText("?", cx, cy);
2842
+ }
2843
+ ctx.restore();
2844
+ }
2845
+
2846
+ // Src/Utils/ShipCard/render.ts
2847
+ async function drawShipCard(ctx, width, height, layout) {
2848
+ const accentColor = layout.accentColor ? parseHex(layout.accentColor) : DEFAULT_ACCENT4;
2849
+ const heartColor = layout.heartColor ? parseHex(layout.heartColor) : accentColor;
2850
+ ctx.save();
2851
+ ctx.beginPath();
2852
+ ctx.roundRect(0, 0, width, height, [CORNER_RADIUS5]);
2853
+ ctx.clip();
2854
+ ctx.fillStyle = "#0c0d11";
2855
+ ctx.fillRect(0, 0, width, height);
2856
+ const backgroundImage = await loadImageSafe(layout.customBackground);
2857
+ if (backgroundImage) {
2858
+ drawCoverImage(ctx, backgroundImage, 0, 0, width, height);
2859
+ ctx.fillStyle = "rgba(8, 9, 13, 0.5)";
2860
+ ctx.fillRect(0, 0, width, height);
2861
+ const duotone = ctx.createLinearGradient(0, 0, width, height);
2862
+ duotone.addColorStop(0, hexToRgba(accentColor, 0.25));
2863
+ duotone.addColorStop(1, "rgba(8, 9, 13, 0.35)");
2864
+ ctx.fillStyle = duotone;
2865
+ ctx.fillRect(0, 0, width, height);
2866
+ } else {
2867
+ const grd = ctx.createLinearGradient(0, 0, width, height);
2868
+ grd.addColorStop(0, hexToRgba(accentColor, 0.32));
2869
+ grd.addColorStop(0.55, "rgba(20, 16, 26, 1)");
2870
+ grd.addColorStop(1, "rgba(10, 11, 15, 1)");
2871
+ ctx.fillStyle = grd;
2872
+ ctx.fillRect(0, 0, width, height);
2873
+ const glow = ctx.createRadialGradient(
2874
+ width / 2,
2875
+ height * 0.62,
2876
+ 10,
2877
+ width / 2,
2878
+ height * 0.62,
2879
+ width * 0.4
2880
+ );
2881
+ glow.addColorStop(0, hexToRgba(accentColor, 0.35));
2882
+ glow.addColorStop(1, "rgba(0, 0, 0, 0)");
2883
+ ctx.fillStyle = glow;
2884
+ ctx.fillRect(0, 0, width, height);
2885
+ }
2886
+ drawVignette(ctx, width, height);
2887
+ drawSparkles(ctx, width, height, heartColor);
2888
+ const showText = layout.showText ?? true;
2889
+ if (showText) {
2890
+ const headerPanel = ctx.createLinearGradient(0, 0, 0, 96);
2891
+ headerPanel.addColorStop(0, "rgba(5, 5, 8, 0.55)");
2892
+ headerPanel.addColorStop(1, "rgba(5, 5, 8, 0)");
2893
+ ctx.fillStyle = headerPanel;
2894
+ ctx.fillRect(0, 0, width, 96);
2895
+ drawHeartIcon(ctx, 34, 32, 18, heartColor);
2896
+ ctx.textAlign = "left";
2897
+ ctx.font = withFallback("13px Helvetica");
2898
+ ctx.fillStyle = "rgba(255, 255, 255, 0.65)";
2899
+ ctx.fillText(`LA COMPATIBILIDAD ES ${layout.percentage}%`.toUpperCase(), 54, 37);
2900
+ ctx.font = withFallback("24px Helvetica Bold");
2901
+ ctx.shadowColor = "rgba(0, 0, 0, 0.6)";
2902
+ ctx.shadowBlur = 12;
2903
+ ctx.shadowOffsetY = 2;
2904
+ ctx.fillStyle = "#FFFFFF";
2905
+ ctx.fillText(truncateText(layout.message, 42), 32, 76);
2906
+ ctx.shadowColor = "transparent";
2907
+ ctx.shadowBlur = 0;
2908
+ ctx.shadowOffsetY = 0;
2909
+ if (layout.shipName) {
2910
+ drawShipNamePill(ctx, width, layout.shipName, accentColor);
2911
+ }
2912
+ }
2913
+ const bandY = showText ? 110 : 20;
2914
+ const bandHeight = height - bandY - (showText ? 26 : 20);
2915
+ const bandCy = bandY + bandHeight / 2;
2916
+ const leftCx = 24 + AVATAR_SIZE2 / 2 + 24;
2917
+ const rightCx = width - 24 - AVATAR_SIZE2 / 2 - 24;
2918
+ const heartWidth = Math.min(
2919
+ HEART_WIDTH,
2920
+ rightCx - AVATAR_SIZE2 / 2 - (leftCx + AVATAR_SIZE2 / 2) - 20
2921
+ );
2922
+ const heartHeight = Math.min(HEART_HEIGHT, bandHeight - 4);
2923
+ drawConnector(
2924
+ ctx,
2925
+ leftCx + AVATAR_SIZE2 / 2 + 10,
2926
+ width / 2 - heartWidth / 2 - 10,
2927
+ bandCy,
2928
+ heartColor
2929
+ );
2930
+ drawConnector(
2931
+ ctx,
2932
+ width / 2 + heartWidth / 2 + 10,
2933
+ rightCx - AVATAR_SIZE2 / 2 - 10,
2934
+ bandCy,
2935
+ heartColor
2936
+ );
2937
+ await drawAvatarCircle(ctx, leftCx, bandCy, layout.leftAvatarUrl, accentColor);
2938
+ await drawAvatarCircle(ctx, rightCx, bandCy, layout.rightAvatarUrl, accentColor);
2939
+ drawHeartMeter(ctx, width / 2, bandCy, heartWidth, heartHeight, layout.percentage, heartColor);
2940
+ ctx.restore();
2941
+ const borderColors = layout.noBorder ? [] : layout.borderColors?.length ? layout.borderColors : [accentColor];
2942
+ if (borderColors.length > 0) {
2943
+ drawGradientBorder(ctx, width, height, borderColors, CORNER_RADIUS5 - 2, 4);
2944
+ }
2945
+ }
2946
+
2947
+ // Src/Utils/shipCard.output.utils.ts
2948
+ async function genShipPng(layout, output) {
2949
+ const { width, height } = getCardDimensions4();
2950
+ const { canvas, ctx } = createShipCanvas(width, height);
2951
+ await drawShipCard(ctx, width, height, layout);
2952
+ return encodeCanvas(canvas, output);
2953
+ }
2954
+
2955
+ // Src/Cards/shipImage.ts
2956
+ async function resolveAvatarUrl(userId, override, guildId, bypassCache) {
2957
+ if (override) return parseImg(override);
2958
+ const data = await fetchUserData(userId, guildId, bypassCache);
2959
+ return data.assets.avatarURL ?? data.assets.defaultAvatarURL;
2960
+ }
2961
+ async function shipImage(leftUserId, rightUserId, options = {}) {
2962
+ if (!leftUserId || typeof leftUserId !== "string") {
2963
+ throw new KiraError("A valid leftUserId is required", "VALIDATION" /* Validation */);
2964
+ }
2965
+ if (!rightUserId || typeof rightUserId !== "string") {
2966
+ throw new KiraError("A valid rightUserId is required", "VALIDATION" /* Validation */);
2967
+ }
2968
+ const bypassCache = options.bypassCache ?? false;
2969
+ const [leftAvatarUrl, rightAvatarUrl] = await Promise.all([
2970
+ resolveAvatarUrl(leftUserId, options.leftImage, options.guildId, bypassCache),
2971
+ resolveAvatarUrl(rightUserId, options.rightImage, options.guildId, bypassCache)
2972
+ ]);
2973
+ const percentage = typeof options.percentage === "number" ? Math.min(100, Math.max(0, Math.round(options.percentage))) : computeCompatibility(leftUserId, rightUserId);
2974
+ const message = options.message ?? pickShipMessage(leftUserId, rightUserId, percentage);
2975
+ const palette = getThemePalette(options.theme);
2976
+ const accentColor = options.accentColor ?? palette?.accentColor;
2977
+ const needsDecoration = Boolean(options.useNitroTheme || options.useRoleColor);
2978
+ const leftData = needsDecoration ? await fetchUserData(leftUserId, options.guildId, bypassCache) : void 0;
2979
+ const borderColors = resolveCardColors({
2980
+ custom: options.borderColor,
2981
+ removeBorder: options.removeBorder,
2982
+ useNitroTheme: options.useNitroTheme,
2983
+ nitroColors: leftData?.decoration.profileColors,
2984
+ useRoleColor: options.useRoleColor,
2985
+ roleColor: leftData?.decoration.roleColor,
2986
+ fallback: palette?.borderColor ?? (accentColor ? [accentColor] : void 0)
2987
+ });
2988
+ const layout = {
2989
+ leftAvatarUrl,
2990
+ rightAvatarUrl,
2991
+ percentage,
2992
+ message,
2993
+ accentColor,
2994
+ borderColors: borderColors.length ? borderColors : void 0,
2995
+ noBorder: options.removeBorder,
2996
+ customBackground: options.customBackground,
2997
+ heartColor: options.heartColor ?? palette?.heartColor,
2998
+ shipName: options.shipName,
2999
+ showText: options.showText
3000
+ };
3001
+ try {
3002
+ return await genShipPng(layout, options.output);
3003
+ } catch (error) {
3004
+ if (error instanceof KiraError) throw error;
3005
+ const message2 = error instanceof Error ? error.message : String(error);
3006
+ throw new KiraError(message2, "RENDER" /* Render */);
3007
+ }
3008
+ }
3009
+
3010
+ // Src/Utils/attachment.utils.ts
3011
+ var import_discord = require("discord.js");
3012
+ function toAttachment(buffer, name = "card", format) {
3013
+ const fileName = name.includes(".") ? name : `${name}.${extensionForFormat(format)}`;
3014
+ return new import_discord.AttachmentBuilder(buffer, { name: fileName });
3015
+ }
3016
+ // Annotate the CommonJS export names for ESM import in node:
3017
+ 0 && (module.exports = {
3018
+ KiraError,
3019
+ KiraErrorCode,
3020
+ THEMES,
3021
+ achievementImage,
3022
+ clearCache,
3023
+ computeCompatibility,
3024
+ decimalToHex,
3025
+ drawCoverImage,
3026
+ drawGradientBorder,
3027
+ encodeCanvas,
3028
+ extensionForFormat,
3029
+ getCacheSize,
3030
+ getThemePalette,
3031
+ hexToRgb,
3032
+ hexToRgba,
3033
+ isNumber,
3034
+ isString,
3035
+ leaderboardImage,
3036
+ leaveImage,
3037
+ levelUpImage,
3038
+ loadImageSafe,
3039
+ parseHex,
3040
+ parseImg,
3041
+ parsePng,
3042
+ pickShipMessage,
3043
+ profileImage,
3044
+ setCacheOptions,
3045
+ setClient,
3046
+ shipImage,
3047
+ toAttachment,
3048
+ welcomeImage
3049
+ });
3050
+ //# sourceMappingURL=index.cjs.map