sweety-html-transcripts 0.2.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.
Files changed (81) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +127 -0
  3. package/dist/adapters/core.d.ts +41 -0
  4. package/dist/adapters/core.js +30 -0
  5. package/dist/adapters/core.js.map +1 -0
  6. package/dist/adapters/discordjs.d.ts +26 -0
  7. package/dist/adapters/discordjs.js +102 -0
  8. package/dist/adapters/discordjs.js.map +1 -0
  9. package/dist/adapters/seyfert.d.ts +26 -0
  10. package/dist/adapters/seyfert.js +67 -0
  11. package/dist/adapters/seyfert.js.map +1 -0
  12. package/dist/downloader/images.d.ts +37 -0
  13. package/dist/downloader/images.js +119 -0
  14. package/dist/downloader/images.js.map +1 -0
  15. package/dist/generator/index.d.ts +34 -0
  16. package/dist/generator/index.js +81 -0
  17. package/dist/generator/index.js.map +1 -0
  18. package/dist/generator/renderers/attachment.d.ts +24 -0
  19. package/dist/generator/renderers/attachment.js +133 -0
  20. package/dist/generator/renderers/attachment.js.map +1 -0
  21. package/dist/generator/renderers/components.d.ts +8 -0
  22. package/dist/generator/renderers/components.js +179 -0
  23. package/dist/generator/renderers/components.js.map +1 -0
  24. package/dist/generator/renderers/content.d.ts +32 -0
  25. package/dist/generator/renderers/content.js +168 -0
  26. package/dist/generator/renderers/content.js.map +1 -0
  27. package/dist/generator/renderers/embed.d.ts +15 -0
  28. package/dist/generator/renderers/embed.js +77 -0
  29. package/dist/generator/renderers/embed.js.map +1 -0
  30. package/dist/generator/renderers/message.d.ts +15 -0
  31. package/dist/generator/renderers/message.js +95 -0
  32. package/dist/generator/renderers/message.js.map +1 -0
  33. package/dist/generator/renderers/reply.d.ts +7 -0
  34. package/dist/generator/renderers/reply.js +76 -0
  35. package/dist/generator/renderers/reply.js.map +1 -0
  36. package/dist/generator/renderers/systemMessage.d.ts +19 -0
  37. package/dist/generator/renderers/systemMessage.js +109 -0
  38. package/dist/generator/renderers/systemMessage.js.map +1 -0
  39. package/dist/generator/transcript.d.ts +12 -0
  40. package/dist/generator/transcript.js +85 -0
  41. package/dist/generator/transcript.js.map +1 -0
  42. package/dist/index.d.ts +26 -0
  43. package/dist/index.js +143 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/static/client.d.ts +2 -0
  46. package/dist/static/client.js +30 -0
  47. package/dist/static/client.js.map +1 -0
  48. package/dist/types.d.ts +69 -0
  49. package/dist/types.js +10 -0
  50. package/dist/types.js.map +1 -0
  51. package/dist/utils/api.d.ts +19 -0
  52. package/dist/utils/api.js +364 -0
  53. package/dist/utils/api.js.map +1 -0
  54. package/dist/utils/cdn.d.ts +28 -0
  55. package/dist/utils/cdn.js +61 -0
  56. package/dist/utils/cdn.js.map +1 -0
  57. package/dist/utils/channel.d.ts +34 -0
  58. package/dist/utils/channel.js +51 -0
  59. package/dist/utils/channel.js.map +1 -0
  60. package/dist/utils/embeds.d.ts +2 -0
  61. package/dist/utils/embeds.js +17 -0
  62. package/dist/utils/embeds.js.map +1 -0
  63. package/dist/utils/guild.d.ts +9 -0
  64. package/dist/utils/guild.js +19 -0
  65. package/dist/utils/guild.js.map +1 -0
  66. package/dist/utils/message.d.ts +6 -0
  67. package/dist/utils/message.js +11 -0
  68. package/dist/utils/message.js.map +1 -0
  69. package/dist/utils/profiles.d.ts +18 -0
  70. package/dist/utils/profiles.js +67 -0
  71. package/dist/utils/profiles.js.map +1 -0
  72. package/dist/utils/replacer.d.ts +28 -0
  73. package/dist/utils/replacer.js +67 -0
  74. package/dist/utils/replacer.js.map +1 -0
  75. package/dist/utils/user.d.ts +18 -0
  76. package/dist/utils/user.js +38 -0
  77. package/dist/utils/user.js.map +1 -0
  78. package/dist/utils/utils.d.ts +32 -0
  79. package/dist/utils/utils.js +61 -0
  80. package/dist/utils/utils.js.map +1 -0
  81. package/package.json +90 -0
@@ -0,0 +1,37 @@
1
+ import type { WebpOptions } from 'sharp';
2
+ import type { APIAttachment, APIMessage, APIMessageSnapshot } from 'discord-api-types/v10';
3
+ import type { Awaitable } from '../adapters/core';
4
+ /**
5
+ * Callback used to save an image attachment.
6
+ * The returned string is the URL that will be used in the transcript.
7
+ *
8
+ * `undefined` indicates to use the original attachment URL.
9
+ * `null` indicates to not include the attachment in the transcript.
10
+ * `string` indicates to use the returned URL as the attachment URL (base64 or remote image).
11
+ */
12
+ export type ResolveImageCallback = (attachment: APIAttachment, message: APIMessage | APIMessageSnapshot['message']) => Awaitable<string | null | undefined>;
13
+ /**
14
+ * Builder to build a image saving callback.
15
+ */
16
+ export declare class TranscriptImageDownloader {
17
+ private static log;
18
+ private log;
19
+ private maxFileSize?;
20
+ private compression?;
21
+ /**
22
+ * Sets the maximum file size for *each* individual image.
23
+ * @param size The maximum file size in kilobytes
24
+ */
25
+ withMaxSize(size: number): this;
26
+ /**
27
+ * Sets the compression quality for each image. This requires `sharp` to be installed.
28
+ * Optionally, images can be converted to WebP format which is smaller in size.
29
+ * @param quality The quality of the image (1 lowest - 100 highest). Lower quality means smaller file size.
30
+ * @param convertToWebP Whether to convert the image to WebP format
31
+ */
32
+ withCompression(quality?: number, convertToWebP?: boolean, options?: Omit<WebpOptions, 'quality' | 'force'>): this;
33
+ /**
34
+ * Builds the image saving callback.
35
+ */
36
+ build(): ResolveImageCallback;
37
+ }
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.TranscriptImageDownloader = void 0;
40
+ const undici_1 = require("undici");
41
+ const debug_1 = __importDefault(require("debug"));
42
+ /**
43
+ * Builder to build a image saving callback.
44
+ */
45
+ class TranscriptImageDownloader {
46
+ constructor() {
47
+ this.log = TranscriptImageDownloader.log;
48
+ }
49
+ /**
50
+ * Sets the maximum file size for *each* individual image.
51
+ * @param size The maximum file size in kilobytes
52
+ */
53
+ withMaxSize(size) {
54
+ this.maxFileSize = size;
55
+ return this;
56
+ }
57
+ /**
58
+ * Sets the compression quality for each image. This requires `sharp` to be installed.
59
+ * Optionally, images can be converted to WebP format which is smaller in size.
60
+ * @param quality The quality of the image (1 lowest - 100 highest). Lower quality means smaller file size.
61
+ * @param convertToWebP Whether to convert the image to WebP format
62
+ */
63
+ withCompression(quality = 80, convertToWebP = false, options = {}) {
64
+ if (quality < 1 || quality > 100)
65
+ throw new Error('Quality must be between 1 and 100');
66
+ // try and import sharp
67
+ Promise.resolve().then(() => __importStar(require('sharp'))).catch((err) => {
68
+ console.error(err);
69
+ console.error(`[sweety-html-transcripts] Failed to import 'sharp'. Image compression requires the 'sharp' package to be installed. Either install sharp or remove the compression options.`);
70
+ });
71
+ this.compression = { quality, convertToWebP, options };
72
+ return this;
73
+ }
74
+ /**
75
+ * Builds the image saving callback.
76
+ */
77
+ build() {
78
+ return async (attachment) => {
79
+ // if the attachment is not an image, return null
80
+ if (!attachment.width || !attachment.height)
81
+ return undefined;
82
+ // if the max file size is set, check if the file size is within the limit
83
+ if (this.maxFileSize && attachment.size > this.maxFileSize * 1024)
84
+ return undefined;
85
+ // fetch the image
86
+ this.log(`Fetching attachment ${attachment.id}: ${attachment.url}`);
87
+ const response = await (0, undici_1.request)(attachment.url).catch((err) => {
88
+ console.error(`[sweety-html-transcripts] Failed to download image for transcript: `, err);
89
+ return null;
90
+ });
91
+ if (!response)
92
+ return undefined;
93
+ const mimetype = response.headers['content-type'];
94
+ const buffer = await response.body.arrayBuffer().then((res) => Buffer.from(res));
95
+ this.log(`Finished fetching ${attachment.id} (${buffer.length} bytes)`);
96
+ // if the compression options are set, compress the image
97
+ if (this.compression) {
98
+ const sharp = await Promise.resolve().then(() => __importStar(require('sharp')));
99
+ this.log(`Compressing ${attachment.id} with 'sharp'`);
100
+ const sharpbuf = await sharp
101
+ .default(buffer)
102
+ .webp({
103
+ quality: this.compression.quality,
104
+ force: this.compression.convertToWebP,
105
+ effort: 2,
106
+ ...this.compression.options,
107
+ })
108
+ .toBuffer({ resolveWithObject: true });
109
+ this.log(`Finished compressing ${attachment.id} (${sharpbuf.info.size} bytes)`);
110
+ return `data:image/${sharpbuf.info.format};base64,${sharpbuf.data.toString('base64')}`;
111
+ }
112
+ // return the base64 string
113
+ return `data:${mimetype};base64,${buffer.toString('base64')}`;
114
+ };
115
+ }
116
+ }
117
+ exports.TranscriptImageDownloader = TranscriptImageDownloader;
118
+ TranscriptImageDownloader.log = (0, debug_1.default)('sweety-html-transcripts:TranscriptImageDownloader');
119
+ //# sourceMappingURL=images.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"images.js","sourceRoot":"","sources":["../../src/downloader/images.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import type { APIGuild, APIRole, APIUser } from 'discord-api-types/v10';
2
+ import type { Awaitable, TranscriptAdapter } from '../adapters/core';
3
+ import type { ResolveImageCallback } from '../downloader/images';
4
+ import type { AllAPIChannel, APIMessageData } from '../utils/channel';
5
+ export type RenderMessageContext = {
6
+ adapter: TranscriptAdapter<unknown>;
7
+ messages: APIMessageData[];
8
+ channel: AllAPIChannel;
9
+ guild?: APIGuild | null;
10
+ callbacks: {
11
+ resolveImageSrc: ResolveImageCallback;
12
+ resolveChannel: (channelId: string) => Awaitable<AllAPIChannel | null>;
13
+ resolveUser: (userId: string) => Awaitable<APIUser | null>;
14
+ resolveRole: (roleId: string) => Awaitable<APIRole | null>;
15
+ };
16
+ poweredBy?: boolean;
17
+ footerText?: string;
18
+ saveImages: boolean;
19
+ favicon: 'guild' | string;
20
+ hydrate: boolean;
21
+ /** @default false */
22
+ lightTheme?: boolean;
23
+ selectMenus?: {
24
+ /** @default true */
25
+ includeUsers?: boolean;
26
+ /** @default true */
27
+ includeRoles?: boolean;
28
+ /** @default true */
29
+ includeChannels?: boolean;
30
+ /** @default 25 */
31
+ channelLimits?: number;
32
+ };
33
+ };
34
+ export default function render(context: RenderMessageContext): Promise<string>;
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.default = render;
7
+ const hydrate_1 = require("@derockdev/discord-components-core/hydrate");
8
+ const react_1 = __importDefault(require("react"));
9
+ const static_1 = require("react-dom/static");
10
+ const package_json_1 = require("../../package.json");
11
+ const client_1 = require("../static/client");
12
+ const profiles_1 = require("../utils/profiles");
13
+ const channel_1 = require("../utils/channel");
14
+ const guild_1 = require("../utils/guild");
15
+ const utils_1 = require("../utils/utils");
16
+ const transcript_1 = __importDefault(require("./transcript"));
17
+ const resolveVersion = (version) => version.replace('^', '').replace('~', '');
18
+ const discordComponentsVersion = resolveVersion(package_json_1.devDependencies['@penwin/discord-components-core']);
19
+ async function render(context) {
20
+ var _a, _b, _c, _d;
21
+ context.lightTheme ?? (context.lightTheme = false);
22
+ context.selectMenus ?? (context.selectMenus = {});
23
+ (_a = context.selectMenus).includeUsers ?? (_a.includeUsers = true);
24
+ (_b = context.selectMenus).includeRoles ?? (_b.includeRoles = true);
25
+ (_c = context.selectMenus).includeChannels ?? (_c.includeChannels = true);
26
+ (_d = context.selectMenus).channelLimits ?? (_d.channelLimits = 25);
27
+ const { adapter, channel, ...options } = context;
28
+ const profiles = await (0, profiles_1.buildProfiles)(context);
29
+ adapter.renderContext.profiles = profiles;
30
+ // tysom sagiriikeda to fix this <3
31
+ const stream = await (0, static_1.prerenderToNodeStream)(react_1.default.createElement("html", null,
32
+ react_1.default.createElement("head", null,
33
+ react_1.default.createElement("meta", { charSet: "utf-8" }),
34
+ react_1.default.createElement("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }),
35
+ react_1.default.createElement("link", { rel: "icon", type: "image/png", href: options.favicon === 'guild'
36
+ ? channel_1.channelUtils.isDM(channel) || channel_1.channelUtils.isDirectory(channel)
37
+ ? undefined
38
+ : ((context.guild ? guild_1.guildUtils.iconURL(context.guild, { size: 16, extension: 'png' }) : undefined) ??
39
+ undefined)
40
+ : options.favicon }),
41
+ react_1.default.createElement("title", null, channel_1.channelUtils.isDM(channel) || channel_1.channelUtils.isDirectory(channel) ? 'Direct Messages' : channel.name),
42
+ react_1.default.createElement("script", { dangerouslySetInnerHTML: {
43
+ __html: client_1.scrollToMessage,
44
+ } }),
45
+ !options.hydrate && (react_1.default.createElement(react_1.default.Fragment, null,
46
+ react_1.default.createElement("script", { dangerouslySetInnerHTML: {
47
+ __html: `window.$discordMessage={profiles:${JSON.stringify(profiles)}}`,
48
+ } }),
49
+ react_1.default.createElement("script", { type: "module", src: `https://cdn.jsdelivr.net/npm/@penwin/discord-components-core@${discordComponentsVersion}/dist/bundle/index.mjs` }))),
50
+ react_1.default.createElement("link", { rel: "stylesheet", href: `https://cdn.jsdelivr.net/npm/@penwin/discord-components-core@${discordComponentsVersion}/dist/bundle/styles/base.css` })),
51
+ react_1.default.createElement("body", { style: {
52
+ margin: 0,
53
+ minHeight: '100vh',
54
+ } },
55
+ react_1.default.createElement(transcript_1.default, { context: context })),
56
+ options.hydrate && react_1.default.createElement("script", { dangerouslySetInnerHTML: { __html: client_1.revealSpoiler } })));
57
+ const markup = await (0, utils_1.streamToString)(stream.prelude);
58
+ if (options.hydrate) {
59
+ const result = await (0, hydrate_1.renderToString)(markup, {
60
+ beforeHydrate: async (document) => {
61
+ document.defaultView.$discordMessage = {
62
+ profiles,
63
+ };
64
+ document.defaultView.$discordSelectMenu = {
65
+ users: !adapter.renderContext.selectMenu.users?.injectedScript
66
+ ? (adapter.renderContext.selectMenu.users?.data ?? [])
67
+ : [],
68
+ roles: !adapter.renderContext.selectMenu.roles?.injectedScript
69
+ ? (adapter.renderContext.selectMenu.roles?.data ?? [])
70
+ : [],
71
+ channels: !adapter.renderContext.selectMenu.channels?.injectedScript
72
+ ? (adapter.renderContext.selectMenu.channels?.data ?? [])
73
+ : [],
74
+ };
75
+ },
76
+ });
77
+ return result.html;
78
+ }
79
+ return markup;
80
+ }
81
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/generator/index.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { APIAttachment, APIMessageSnapshot } from 'discord-api-types/v10';
2
+ import React from 'react';
3
+ import type { RenderMessageContext } from '..';
4
+ import type { APIMessageData } from '../../utils/channel';
5
+ /**
6
+ * Renders all attachments for a message
7
+ * @param message
8
+ * @param context
9
+ * @returns
10
+ */
11
+ export declare function Attachments(props: {
12
+ message: APIMessageData | APIMessageSnapshot['message'];
13
+ context: RenderMessageContext;
14
+ }): Promise<React.JSX.Element>;
15
+ /**
16
+ * Renders one Discord Attachment
17
+ * @param props - the attachment and rendering context
18
+ */
19
+ export declare function Attachment({ attachment, context, message, isVoiceMessage, }: {
20
+ attachment: APIAttachment;
21
+ context: RenderMessageContext;
22
+ message: APIMessageData | APIMessageSnapshot['message'];
23
+ isVoiceMessage?: boolean;
24
+ }): Promise<React.JSX.Element>;
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Attachments = Attachments;
7
+ exports.Attachment = Attachment;
8
+ const discord_components_react_render_1 = require("@penwin/discord-components-react-render");
9
+ const v10_1 = require("discord-api-types/v10");
10
+ const react_1 = __importDefault(require("react"));
11
+ const utils_1 = require("../../utils/utils");
12
+ function getAttachmentType(attachment) {
13
+ const type = attachment.content_type?.split('/')?.[0] ?? 'unknown';
14
+ if (['audio', 'video', 'image'].includes(type))
15
+ return type;
16
+ return 'file';
17
+ }
18
+ /**
19
+ * Renders all attachments for a message
20
+ * @param message
21
+ * @param context
22
+ * @returns
23
+ */
24
+ async function Attachments(props) {
25
+ if (props.message.attachments.length === 0)
26
+ return react_1.default.createElement(react_1.default.Fragment, null);
27
+ const grouped = {
28
+ mediaGallery: [],
29
+ other: [],
30
+ };
31
+ for (const attachment of props.message.attachments) {
32
+ const type = getAttachmentType(attachment);
33
+ if (type === 'image' || type === 'video') {
34
+ grouped.mediaGallery.push(attachment);
35
+ }
36
+ else {
37
+ grouped.other.push(attachment);
38
+ }
39
+ }
40
+ const isVoiceMessage = props.message.flags
41
+ ? (props.message.flags & v10_1.MessageFlags.IsVoiceMessage) === v10_1.MessageFlags.IsVoiceMessage
42
+ : false;
43
+ return (react_1.default.createElement(discord_components_react_render_1.DiscordAttachments, { slot: "attachments" },
44
+ grouped.mediaGallery.length > 0 && (react_1.default.createElement(discord_components_react_render_1.DiscordMediaGallery, null, grouped.mediaGallery.map((attachment, id) => (react_1.default.createElement(Attachment, { attachment: attachment, message: props.message, context: props.context, key: id }))))),
45
+ grouped.other.map((attachment, id) => (react_1.default.createElement(Attachment, { attachment: attachment, message: props.message, context: props.context, key: id, isVoiceMessage: isVoiceMessage })))));
46
+ }
47
+ const programmingLanguageMimeMap = new Map([
48
+ ['text/html', 'html'],
49
+ ['text/css', 'css'],
50
+ ['text/javascript', 'javascript'],
51
+ ['application/javascript', 'javascript'],
52
+ ['application/json', 'json'],
53
+ ['application/xml', 'xml'],
54
+ ['image/svg+xml', 'svg'],
55
+ ['application/xhtml+xml', 'xhtml'],
56
+ ['application/wasm', 'wasm'],
57
+ ['text/markdown', 'markdown'],
58
+ ['text/x-sass', 'sass'],
59
+ ['text/x-scss', 'scss'],
60
+ ['text/x-python', 'python'],
61
+ ['application/x-python-code', 'python'],
62
+ ['text/x-java-source', 'java'],
63
+ ['text/x-csharp', 'csharp'],
64
+ ['text/x-php', 'php'],
65
+ ['application/x-php', 'php'],
66
+ ['text/x-ruby', 'ruby'],
67
+ ['text/x-go', 'go'],
68
+ ['text/x-rustsrc', 'rust'],
69
+ ['text/x-kotlin', 'kotlin'],
70
+ ['text/x-swift', 'swift'],
71
+ ['text/x-dart', 'dart'],
72
+ ['text/x-lua', 'lua'],
73
+ ['text/x-scala', 'scala'],
74
+ ['application/sql', 'sql'],
75
+ ['text/x-sh', 'bash'],
76
+ ['application/x-sh', 'bash'],
77
+ ['text/x-objectivec', 'objectivec'],
78
+ ['text/x-perl', 'perl'],
79
+ ['text/x-pascal', 'pascal'],
80
+ ['text/x-dsrc', 'd'],
81
+ ['text/x-groovy', 'groovy'],
82
+ ['text/x-rsrc', 'r'],
83
+ ['text/x-vb', 'vbnet'],
84
+ ['text/x-solidity', 'solidity'],
85
+ ['text/x-julia', 'julia'],
86
+ ['text/x-clojure', 'clojure'],
87
+ ['application/graphql', 'graphql'],
88
+ ['application/x-yaml', 'yaml'],
89
+ ['text/x-ini', 'ini'],
90
+ ['text/plain', 'plaintext'],
91
+ ['text/uri-list', 'uri'],
92
+ ['application/diff', 'diff'],
93
+ ['text/x-dockerfile', 'dockerfile'],
94
+ ]);
95
+ /**
96
+ * Renders one Discord Attachment
97
+ * @param props - the attachment and rendering context
98
+ */
99
+ async function Attachment({ attachment, context, message, isVoiceMessage, }) {
100
+ let url = attachment.url;
101
+ const type = getAttachmentType(attachment);
102
+ const attach = ('data' in attachment ? attachment.data : attachment);
103
+ if (isVoiceMessage) {
104
+ return react_1.default.createElement(discord_components_react_render_1.DiscordVoiceMessage, { key: attachment.id, href: attachment.url, waveform: attachment.waveform });
105
+ }
106
+ if (type === 'image' || type === 'video') {
107
+ // download it to a data url
108
+ const downloaded = await context.callbacks.resolveImageSrc(attach, message);
109
+ if (downloaded !== null) {
110
+ url = downloaded ?? url;
111
+ }
112
+ return (react_1.default.createElement(discord_components_react_render_1.DiscordMediaGalleryItem, { spoiler: (0, utils_1.hasFlag)({ bitfield: attach.flags, flag: 8 }), media: url, key: attachment.id, description: attachment.description, "mime-type": attachment.content_type, width: attachment.width ?? void 0, height: attachment.height ?? void 0 }));
113
+ }
114
+ // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain
115
+ const mime = attachment.content_type?.split(';')[0];
116
+ const format = programmingLanguageMimeMap.get(mime);
117
+ const { size, unit } = (0, utils_1.formatBytes)(attachment.size);
118
+ if (type === 'audio') {
119
+ return (react_1.default.createElement(discord_components_react_render_1.DiscordAudioAttachment, { key: attachment.id, href: url, bytes: size, "bytes-unit": unit, name: attachment.filename }));
120
+ }
121
+ if (type === 'file') {
122
+ if (format && size <= 1024 * 1024) {
123
+ const content = await fetch(attach.url)
124
+ .then((res) => res.text())
125
+ .catch(() => null);
126
+ if (content) {
127
+ return (react_1.default.createElement(discord_components_react_render_1.DiscordTextFileAttachmentPreviewer, { href: url, name: attachment.filename, language: format, bytes: size, "bytes-unit": unit, key: attachment.id, content: content }));
128
+ }
129
+ }
130
+ }
131
+ return (react_1.default.createElement(discord_components_react_render_1.DiscordFileAttachment, { type: type, bytes: size, "bytes-unit": unit, name: attachment.filename, key: attachment.id, href: url }));
132
+ }
133
+ //# sourceMappingURL=attachment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachment.js","sourceRoot":"","sources":["../../../src/generator/renderers/attachment.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import type { APIMessageComponent } from 'discord-api-types/v10';
3
+ import type { RenderMessageContext } from '..';
4
+ export declare function Component({ component, id, context, }: {
5
+ component: APIMessageComponent;
6
+ id: number;
7
+ context: RenderMessageContext;
8
+ }): Promise<React.JSX.Element>;
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.Component = Component;
40
+ const discord_components_react_render_1 = require("@penwin/discord-components-react-render");
41
+ const react_1 = __importDefault(require("react"));
42
+ const v10_1 = require("discord-api-types/v10");
43
+ const utils_1 = require("../../utils/utils");
44
+ const content_1 = __importStar(require("./content"));
45
+ const guild_1 = require("../../utils/guild");
46
+ const selectMenuScriptHeader = `(window.$discordSelectMenu ??= {})`;
47
+ const ButtonStyleMapping = {
48
+ [v10_1.ButtonStyle.Primary]: 'primary',
49
+ [v10_1.ButtonStyle.Secondary]: 'secondary',
50
+ [v10_1.ButtonStyle.Success]: 'success',
51
+ [v10_1.ButtonStyle.Danger]: 'destructive',
52
+ [v10_1.ButtonStyle.Link]: 'secondary',
53
+ [v10_1.ButtonStyle.Premium]: 'premium',
54
+ };
55
+ async function Component({ component, id, context, }) {
56
+ switch (component.type) {
57
+ case v10_1.ComponentType.Button:
58
+ return (react_1.default.createElement(discord_components_react_render_1.DiscordButton, { key: id, type: 'style' in component ? ButtonStyleMapping[component.style] : 'secondary', url: 'url' in component ? component.url : undefined, emoji: 'emoji' in component ? (0, utils_1.parseDiscordEmoji)(component.emoji) : undefined, disabled: component.disabled }, 'label' in component ? component.label : undefined));
59
+ case v10_1.ComponentType.ActionRow: {
60
+ return (react_1.default.createElement(discord_components_react_render_1.DiscordActionRow, { key: id }, component.components.map((component, id) => (react_1.default.createElement(Component, { component: component, id: id, key: id, context: context })))));
61
+ }
62
+ case v10_1.ComponentType.Container: {
63
+ return (react_1.default.createElement(discord_components_react_render_1.DiscordContainer, { key: id, spoiler: component.spoiler },
64
+ react_1.default.createElement(discord_components_react_render_1.DiscordComponentsColumn, null, component.components.map((component, id) => (react_1.default.createElement(Component, { component: component, id: id, key: id, context: context }))))));
65
+ }
66
+ case v10_1.ComponentType.Thumbnail: {
67
+ return (react_1.default.createElement(discord_components_react_render_1.DiscordThumbnail, { key: id, media: component.media.proxy_url ?? component.media.url, spoiler: component.spoiler }));
68
+ }
69
+ case v10_1.ComponentType.Section: {
70
+ return (react_1.default.createElement(discord_components_react_render_1.DiscordSection, { key: id },
71
+ react_1.default.createElement(discord_components_react_render_1.DiscordSectionComponents, null, component.components.map((component, id) => (react_1.default.createElement(Component, { component: component, id: id, key: id, context: context })))),
72
+ react_1.default.createElement(Component, { component: component.accessory, id: id, key: id, context: context })));
73
+ }
74
+ case v10_1.ComponentType.TextDisplay: {
75
+ return (react_1.default.createElement(discord_components_react_render_1.DiscordTextDisplay, { key: id },
76
+ react_1.default.createElement(content_1.default, { content: component.content, context: { ...context, type: content_1.RenderType.EMBED } })));
77
+ }
78
+ case v10_1.ComponentType.Separator: {
79
+ return react_1.default.createElement(discord_components_react_render_1.DiscordSeparator, { key: id, spacing: component.spacing, divider: component.divider });
80
+ }
81
+ case v10_1.ComponentType.File: {
82
+ const resolvedFileComponent = component;
83
+ const { size, unit } = (0, utils_1.formatBytes)(resolvedFileComponent.size);
84
+ return (react_1.default.createElement(discord_components_react_render_1.DiscordFileAttachment, { key: id, name: resolvedFileComponent.name, bytes: size, "bytes-unit": unit, href: component.file.proxy_url ?? component.file.url, spoiler: component.spoiler }));
85
+ }
86
+ case v10_1.ComponentType.MediaGallery: {
87
+ return (react_1.default.createElement(discord_components_react_render_1.DiscordMediaGallery, { key: id }, component.items.map((item, id) => (react_1.default.createElement(discord_components_react_render_1.DiscordMediaGalleryItem, { key: `${id}-${component.id}`, media: item.media.proxy_url ?? item.media.url, "mime-type": item.media.content_type, spoiler: item.spoiler, description: item.description ?? void 0, width: item.media.width ?? void 0, height: item.media.height ?? void 0 })))));
88
+ }
89
+ case v10_1.ComponentType.StringSelect:
90
+ case v10_1.ComponentType.SelectMenu: {
91
+ return (react_1.default.createElement(discord_components_react_render_1.DiscordStringSelectMenu, { disabled: component.disabled, placeholder: component.placeholder }, component.options.map((option, id) => (react_1.default.createElement(discord_components_react_render_1.DiscordStringSelectMenuOption, { key: id, label: option.label, description: option.description, emojiName: option.emoji?.name, emoji: option.emoji && (0, utils_1.parseDiscordEmoji)(option.emoji), selected: option.default })))));
92
+ }
93
+ case v10_1.ComponentType.ChannelSelect:
94
+ case v10_1.ComponentType.RoleSelect:
95
+ case v10_1.ComponentType.MentionableSelect:
96
+ case v10_1.ComponentType.UserSelect: {
97
+ const isMentionable = component.type === v10_1.ComponentType.MentionableSelect;
98
+ const isUser = component.type === v10_1.ComponentType.UserSelect;
99
+ const isRole = component.type === v10_1.ComponentType.RoleSelect;
100
+ const isChannel = component.type === v10_1.ComponentType.ChannelSelect;
101
+ const containsUsers = (isMentionable || isUser) && context.selectMenus?.includeUsers;
102
+ const containsRoles = isRole && context.selectMenus?.includeRoles;
103
+ const containsChannels = isChannel && context.selectMenus?.includeChannels;
104
+ const scripts = [];
105
+ if (containsUsers && !context.adapter.renderContext.selectMenu.users) {
106
+ context.adapter.renderContext.selectMenu.users = {
107
+ data: Object.entries(context.adapter.renderContext.profiles).map(([id, profile]) => ({
108
+ identifier: id,
109
+ discriminator: profile.discriminator,
110
+ avatarUrl: profile.avatar,
111
+ username: profile.author,
112
+ globalName: profile.displayName ?? profile.globalName,
113
+ bot: profile.bot,
114
+ verified: profile.verified,
115
+ })),
116
+ injectedScript: !context.hydrate,
117
+ };
118
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
119
+ !context.hydrate &&
120
+ scripts.push(react_1.default.createElement("script", { key: 'users-script', dangerouslySetInnerHTML: {
121
+ __html: `${selectMenuScriptHeader}.users = ${JSON.stringify(context.adapter.renderContext.selectMenu.users.data)}`,
122
+ } }));
123
+ }
124
+ if (containsRoles && !context.adapter.renderContext.selectMenu.roles && context.guild?.id) {
125
+ const data = [];
126
+ const roles = await context.adapter.resolveGuildRoles(context.guild?.id);
127
+ for (const role of roles) {
128
+ if (role.id === context.guild?.id)
129
+ continue;
130
+ data.push({
131
+ identifier: role.id,
132
+ name: role.name,
133
+ color: (0, utils_1.convertToHEX)(role.color),
134
+ iconUrl: (role.icon && guild_1.guildUtils.roleIcon(role.id, role.icon)) ?? void 0,
135
+ memberCount: 0,
136
+ showMemberCount: false,
137
+ });
138
+ }
139
+ context.adapter.renderContext.selectMenu.roles = {
140
+ data,
141
+ injectedScript: !context.hydrate,
142
+ };
143
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
144
+ !context.hydrate &&
145
+ scripts.push(react_1.default.createElement("script", { key: 'roles-script', dangerouslySetInnerHTML: {
146
+ __html: `${selectMenuScriptHeader}.roles = ${JSON.stringify(context.adapter.renderContext.selectMenu.roles.data)}`,
147
+ } }));
148
+ }
149
+ if (containsChannels && !context.adapter.renderContext.selectMenu.channels && context.guild?.id) {
150
+ const data = [];
151
+ const channels = await context.adapter.resolveGuildChannels(context.guild?.id);
152
+ for (const channel of channels) {
153
+ if (data.length >= (context.selectMenus?.channelLimits ?? 25))
154
+ break;
155
+ if ('name' in channel && channel.name) {
156
+ data.push({
157
+ identifier: channel.id,
158
+ name: channel.name,
159
+ type: channel.type,
160
+ });
161
+ }
162
+ }
163
+ context.adapter.renderContext.selectMenu.channels = {
164
+ data,
165
+ injectedScript: !context.hydrate,
166
+ };
167
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
168
+ !context.hydrate &&
169
+ scripts.push(react_1.default.createElement("script", { key: 'channels-script', dangerouslySetInnerHTML: {
170
+ __html: `${selectMenuScriptHeader}.channels = ${JSON.stringify(context.adapter.renderContext.selectMenu.channels.data)}`,
171
+ } }));
172
+ }
173
+ return (react_1.default.createElement(react_1.default.Fragment, null,
174
+ scripts,
175
+ react_1.default.createElement(discord_components_react_render_1.DiscordSelectMenuPortal, { key: id, disabled: component.disabled, placeholder: component.placeholder, type: isMentionable ? 'mentionable' : isUser ? 'user' : isRole ? 'role' : 'channel', "default-identifier": component.default_values?.[0].id, "default-type": component.default_values?.[0].type })));
176
+ }
177
+ }
178
+ }
179
+ //# sourceMappingURL=components.js.map