From 0e3ff586035c374171e6801dd823a04d1101f665 Mon Sep 17 00:00:00 2001 From: thororen <78185467+thororen1234@users.noreply.github.com> Date: Thu, 29 Oct 2026 23:12:48 -0400 Subject: [PATCH 1/5] author and contributor as obj --- bundle/lib/plugins/src/_internal/manifest.ts | 3 ++ bundle/lib/plugins/src/_internal/types.ts | 6 ++- bundle/lib/plugins/src/types.ts | 1 + bundle/lib/plugins/src/utils.test.ts | 39 +++++++++++++- bundle/lib/plugins/src/utils.ts | 27 ++++++++++ bundle/scripts/manifest.ts | 19 +++++-- .../plugins/preinit/api.hidden/manifest.json | 2 +- .../plugins/preinit/api.themes/manifest.json | 2 +- bundle/src/plugins/preinit/api/manifest.json | 2 +- .../src/plugins/preinit/logging/manifest.json | 2 +- .../plugins/preinit/no-track/manifest.json | 2 +- .../plugins/preinit/recovery/manifest.json | 2 +- .../start/settings.plugins/manifest.json | 2 +- .../start/settings.themes/manifest.json | 2 +- .../src/plugins/start/settings/manifest.json | 2 +- .../start/staff-settings/manifest.json | 2 +- .../plugins/start/user-badges/manifest.json | 2 +- .../app/valenced/plugins/Contributor.kt | 52 +++++++++++++++++++ .../plugins/external/ExternalManifest.kt | 6 ++- .../app/valenced/plugins/repos/RepoIndex.kt | 6 ++- .../plugins/external/ExternalManifestTest.kt | 24 +++++++++ 21 files changed, 184 insertions(+), 21 deletions(-) create mode 100644 core/src/commonMain/kotlin/app/valenced/plugins/Contributor.kt diff --git a/bundle/lib/plugins/src/_internal/manifest.ts b/bundle/lib/plugins/src/_internal/manifest.ts index 566835b4..26e156d3 100644 --- a/bundle/lib/plugins/src/_internal/manifest.ts +++ b/bundle/lib/plugins/src/_internal/manifest.ts @@ -1,4 +1,5 @@ import type { PluginManifest, PluginVersion } from '../types' +import { formatPluginContributor } from '../utils' import type { InternalPluginManifest } from './types' /** Manifest schema version internal plugins are written against. */ @@ -39,6 +40,8 @@ export function completeInternalManifest( ? parseBundleVersion(manifest.version) : (manifest.version ?? version) manifest.format ??= ManifestFormat + manifest.author = formatPluginContributor(manifest.author) + manifest.contributors = manifest.contributors?.map(formatPluginContributor) if (!isReservedDependency(manifest.id)) { manifest.dependencies ??= {} diff --git a/bundle/lib/plugins/src/_internal/types.ts b/bundle/lib/plugins/src/_internal/types.ts index 1101b6b4..a3118c64 100644 --- a/bundle/lib/plugins/src/_internal/types.ts +++ b/bundle/lib/plugins/src/_internal/types.ts @@ -5,6 +5,7 @@ import type { PluginOptions, PluginOptionsFactory, } from '../types' +import type { PluginContributorInput } from '../utils' import type { PluginSystemErrorPayload } from './errors' import type { addPluginFlags, adoptPluginFlags } from './state' @@ -12,9 +13,12 @@ export type AnyPlugin = Plugin export type InternalPluginManifest = Omit< PluginManifest, - 'version' | 'format' | 'dependencies' + 'version' | 'format' | 'dependencies' | 'author' | 'contributors' > & Partial> & { + /** Contributor object, or legacy string. Normalized to the string form. */ + author: PluginContributorInput | string + contributors?: (PluginContributorInput | string)[] /** * Plugin version. Defaults to the bundle version. * Only stubs (see {@link InternalPluginManifestExtras.defaultSource}) may set it in `manifest.json`, as a string like `1.0.0`. diff --git a/bundle/lib/plugins/src/types.ts b/bundle/lib/plugins/src/types.ts index 0b2365a2..38378c2b 100644 --- a/bundle/lib/plugins/src/types.ts +++ b/bundle/lib/plugins/src/types.ts @@ -140,6 +140,7 @@ export interface PluginManifest { /** * Author information, as `Name (LINK "LABEL")`. * Discord IDs and links are optional and repeatable. + * `manifest.json` should use the object form ({@link PluginContributorInput}) instead, normalized into this string. * * Use {@link getPluginContributorName} and {@link parsePluginContributor} to extract the name, IDs, and links. */ diff --git a/bundle/lib/plugins/src/utils.test.ts b/bundle/lib/plugins/src/utils.test.ts index 408372ad..f35207e4 100644 --- a/bundle/lib/plugins/src/utils.test.ts +++ b/bundle/lib/plugins/src/utils.test.ts @@ -1,5 +1,9 @@ import { describe, expect, test } from 'vitest' -import { getPluginContributorName, parsePluginContributor } from './utils' +import { + formatPluginContributor, + getPluginContributorName, + parsePluginContributor, +} from './utils' const Id1 = '123456789012345678' const Id2 = '876543210987654321' @@ -64,3 +68,36 @@ describe('getPluginContributorName', () => { expect(getPluginContributorName('Jane (Doe)')).toBe('Jane (Doe)') }) }) + +describe('formatPluginContributor', () => { + test('passes strings through', () => { + expect(formatPluginContributor(`Jane <${Id1}>`)).toBe(`Jane <${Id1}>`) + }) + + test('formats objects into a parseable string', () => { + const formatted = formatPluginContributor({ + name: 'Jane Doe', + ids: [Id1, Id2], + links: [ + { url: 'https://example.com/jane', title: 'Website' }, + { url: 'mailto:jane@example.com' }, + ], + }) + + expect(formatted).toBe( + `Jane Doe <${Id1}> <${Id2}> (https://example.com/jane "Website") (mailto:jane@example.com)`, + ) + expect(parsePluginContributor(formatted)).toEqual({ + name: 'Jane Doe', + ids: [Id1, Id2], + links: [ + { url: 'https://example.com/jane', label: 'Website' }, + { url: 'mailto:jane@example.com', label: undefined }, + ], + }) + }) + + test('formats a name only', () => { + expect(formatPluginContributor({ name: 'Valenced' })).toBe('Valenced') + }) +}) diff --git a/bundle/lib/plugins/src/utils.ts b/bundle/lib/plugins/src/utils.ts index ddb2b388..ddb54c94 100644 --- a/bundle/lib/plugins/src/utils.ts +++ b/bundle/lib/plugins/src/utils.ts @@ -19,6 +19,33 @@ export interface PluginContributorLink { label?: string } +/** + * Contributor as written in `manifest.json`. Preferred over the legacy `Name (LINK "TITLE")` string, + * which is still accepted. + */ +export interface PluginContributorInput { + name: string + /** Discord user IDs. */ + ids?: string[] + links?: { url: string; title?: string }[] +} + +/** Formats a contributor into the `Name (LINK "TITLE")` string form. Legacy strings pass through. */ +export function formatPluginContributor( + contributor: PluginContributorInput | string, +): string { + if (typeof contributor === 'string') return contributor + + const { name, ids = [], links = [] } = contributor + return [ + name.trim(), + ...ids.map(id => `<${id}>`), + ...links.map(({ url, title }) => + title === undefined ? `(${url})` : `(${url} "${title}")`, + ), + ].join(' ') +} + const ContributorEntryRegex = /^(?:<(\d{17,20})>|\(((?:https?:\/\/|mailto:)[^()\s]+)(?:\s+"([^"()]+)")?\))\s*/i diff --git a/bundle/scripts/manifest.ts b/bundle/scripts/manifest.ts index 20945636..04ed3268 100644 --- a/bundle/scripts/manifest.ts +++ b/bundle/scripts/manifest.ts @@ -2,6 +2,7 @@ import { readdir, readFile } from 'fs/promises' import { dirname } from 'path' import { fileURLToPath } from 'url' import { ReservedDependencyIds } from '../lib/plugins/src/_internal/manifest' +import { formatPluginContributor } from '../lib/plugins/src/utils' import { exists, stringEnv } from './_shared' import type { InternalPluginManifest } from '@valenced/plugins/_' @@ -31,8 +32,14 @@ interface BundleManifestPlugin { } interface RawBundleManifestPlugin - extends Omit, - Pick { + extends Omit< + BundleManifestPlugin, + 'enabledByDefault' | 'defaultSource' | 'author' | 'contributors' + >, + Pick< + InternalPluginManifest, + 'enabledByDefault' | 'defaultSource' | 'author' | 'contributors' + > { build?: { devOnly?: boolean } @@ -114,8 +121,12 @@ export async function getInternalPluginManifests( ...(defaultSource && { name: manifest.name, description: manifest.description, - author: manifest.author, - contributors: manifest.contributors, + author: + manifest.author && + formatPluginContributor(manifest.author), + contributors: manifest.contributors?.map( + formatPluginContributor, + ), icon: manifest.icon, }), ...(manifest.essential && { essential: true }), diff --git a/bundle/src/plugins/preinit/api.hidden/manifest.json b/bundle/src/plugins/preinit/api.hidden/manifest.json index 7dc938c1..04465bea 100644 --- a/bundle/src/plugins/preinit/api.hidden/manifest.json +++ b/bundle/src/plugins/preinit/api.hidden/manifest.json @@ -2,7 +2,7 @@ "id": "valenced.api.hidden", "name": "Developer Mode", "description": "Exposes internal Valenced APIs for debugging.", - "author": "Valenced", + "author": { "name": "Valenced" }, "icon": "WrenchIcon", "enabledByDefault": "dev" } diff --git a/bundle/src/plugins/preinit/api.themes/manifest.json b/bundle/src/plugins/preinit/api.themes/manifest.json index 822df215..ef44710a 100644 --- a/bundle/src/plugins/preinit/api.themes/manifest.json +++ b/bundle/src/plugins/preinit/api.themes/manifest.json @@ -2,7 +2,7 @@ "id": "valenced.api.themes", "name": "Themes API", "description": "This feature requires an update to be installed.", - "author": "Valenced", + "author": { "name": "Valenced" }, "icon": "PaintPaletteIcon", "version": "0.0.0", "enabledByDefault": true, diff --git a/bundle/src/plugins/preinit/api/manifest.json b/bundle/src/plugins/preinit/api/manifest.json index 469299ce..6ad226f6 100644 --- a/bundle/src/plugins/preinit/api/manifest.json +++ b/bundle/src/plugins/preinit/api/manifest.json @@ -2,7 +2,7 @@ "id": "valenced.api", "name": "Plugin API", "description": "Provides the Valenced plugin API.", - "author": "Valenced", + "author": { "name": "Valenced" }, "icon": "PollsIcon", "essential": true, "api": true diff --git a/bundle/src/plugins/preinit/logging/manifest.json b/bundle/src/plugins/preinit/logging/manifest.json index 5e98dcc5..87ceb21f 100644 --- a/bundle/src/plugins/preinit/logging/manifest.json +++ b/bundle/src/plugins/preinit/logging/manifest.json @@ -2,7 +2,7 @@ "id": "valenced.logging", "name": "Logging", "description": "Logs assisting Valenced developers.", - "author": "Valenced", + "author": { "name": "Valenced" }, "icon": "PaperIcon", "enabledByDefault": true, "build": { diff --git a/bundle/src/plugins/preinit/no-track/manifest.json b/bundle/src/plugins/preinit/no-track/manifest.json index b7985fed..2353b568 100644 --- a/bundle/src/plugins/preinit/no-track/manifest.json +++ b/bundle/src/plugins/preinit/no-track/manifest.json @@ -2,7 +2,7 @@ "id": "valenced.no-track", "name": "No Track", "description": "Disables Discord and Sentry analytics.", - "author": "Valenced", + "author": { "name": "Valenced" }, "icon": "AnalyticsIcon", "enabledByDefault": true } diff --git a/bundle/src/plugins/preinit/recovery/manifest.json b/bundle/src/plugins/preinit/recovery/manifest.json index 0731aaba..5ceb8551 100644 --- a/bundle/src/plugins/preinit/recovery/manifest.json +++ b/bundle/src/plugins/preinit/recovery/manifest.json @@ -2,7 +2,7 @@ "id": "valenced.recovery", "name": "Recovery", "description": "Handles errors and provides troubleshooting options for Valenced.", - "author": "Valenced", + "author": { "name": "Valenced" }, "icon": "ShieldIcon", "essential": true, "dependencies": { diff --git a/bundle/src/plugins/start/settings.plugins/manifest.json b/bundle/src/plugins/start/settings.plugins/manifest.json index b4955e3c..31ffc7ae 100644 --- a/bundle/src/plugins/start/settings.plugins/manifest.json +++ b/bundle/src/plugins/start/settings.plugins/manifest.json @@ -2,7 +2,7 @@ "id": "valenced.settings.plugins", "name": "Plugin Settings", "description": "Plugin management UI for Valenced.", - "author": "Valenced", + "author": { "name": "Valenced" }, "icon": "PuzzlePieceIcon", "essential": true, "dependencies": { diff --git a/bundle/src/plugins/start/settings.themes/manifest.json b/bundle/src/plugins/start/settings.themes/manifest.json index f5e60c67..b61d9aa5 100644 --- a/bundle/src/plugins/start/settings.themes/manifest.json +++ b/bundle/src/plugins/start/settings.themes/manifest.json @@ -2,7 +2,7 @@ "id": "valenced.settings.themes", "name": "Themes", "description": "This feature requires an update to be installed.", - "author": "Valenced", + "author": { "name": "Valenced" }, "icon": "PaintPaletteIcon", "version": "0.0.0", "enabledByDefault": true, diff --git a/bundle/src/plugins/start/settings/manifest.json b/bundle/src/plugins/start/settings/manifest.json index 5e5a4f95..a5516bde 100644 --- a/bundle/src/plugins/start/settings/manifest.json +++ b/bundle/src/plugins/start/settings/manifest.json @@ -2,7 +2,7 @@ "id": "valenced.settings", "name": "Settings", "description": "Settings UI for Valenced.", - "author": "Valenced", + "author": { "name": "Valenced" }, "icon": "SettingsIcon", "essential": true } diff --git a/bundle/src/plugins/start/staff-settings/manifest.json b/bundle/src/plugins/start/staff-settings/manifest.json index 242211bf..aeee8d4c 100644 --- a/bundle/src/plugins/start/staff-settings/manifest.json +++ b/bundle/src/plugins/start/staff-settings/manifest.json @@ -2,7 +2,7 @@ "id": "valenced.staff-settings", "name": "Staff Settings", "description": "Allows accessing Discord's Staff Settings.", - "author": "Valenced", + "author": { "name": "Valenced" }, "icon": "StaffBadgeIcon", "enabledByDefault": true } diff --git a/bundle/src/plugins/start/user-badges/manifest.json b/bundle/src/plugins/start/user-badges/manifest.json index e9876857..931fe64e 100644 --- a/bundle/src/plugins/start/user-badges/manifest.json +++ b/bundle/src/plugins/start/user-badges/manifest.json @@ -2,7 +2,7 @@ "id": "valenced.user-badges", "name": "User Badges", "description": "Badges for Valenced contributors and sponsors.", - "author": "Valenced", + "author": { "name": "Valenced" }, "icon": "ShieldUserIcon", "essential": true } diff --git a/core/src/commonMain/kotlin/app/valenced/plugins/Contributor.kt b/core/src/commonMain/kotlin/app/valenced/plugins/Contributor.kt new file mode 100644 index 00000000..c44c2852 --- /dev/null +++ b/core/src/commonMain/kotlin/app/valenced/plugins/Contributor.kt @@ -0,0 +1,52 @@ +package app.valenced.plugins + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import kotlinx.serialization.json.JsonDecoder +import kotlinx.serialization.json.JsonPrimitive + +/** + * Contributor as written in manifests: `{ "name": "...", "ids"?: [""], "links"?: [{ "url": "...", "title"?: "..." }] }`. + * Preferred over the legacy `Name (LINK "TITLE")` string, which is still accepted. + * + * Decoded into the string form of [PluginManifest.author]. + */ +@Serializable +internal data class ContributorObject( + val name: String, + /** Discord user IDs. */ + val ids: List = emptyList(), + val links: List = emptyList(), +) { + @Serializable + data class Link(val url: String, val title: String? = null) + + fun format() = buildString { + append(name.trim()) + for (id in ids) append(" <").append(id).append('>') + for ((url, title) in links) { + append(" (").append(url) + if (title != null) append(" \"").append(title).append('"') + append(')') + } + } +} + +/** Accepts a [ContributorObject] or a legacy contributor string, always decoding to the string form. */ +object ContributorSerializer : KSerializer { + override val descriptor = PrimitiveSerialDescriptor("app.valenced.plugins.Contributor", PrimitiveKind.STRING) + + override fun serialize(encoder: Encoder, value: String) = encoder.encodeString(value) + + override fun deserialize(decoder: Decoder): String { + if (decoder !is JsonDecoder) return decoder.decodeString() + + val element = decoder.decodeJsonElement() + if (element is JsonPrimitive && element.isString) return element.content + return decoder.json.decodeFromJsonElement(ContributorObject.serializer(), element).format() + } +} diff --git a/core/src/commonMain/kotlin/app/valenced/plugins/external/ExternalManifest.kt b/core/src/commonMain/kotlin/app/valenced/plugins/external/ExternalManifest.kt index c4dd8fdc..815999ca 100644 --- a/core/src/commonMain/kotlin/app/valenced/plugins/external/ExternalManifest.kt +++ b/core/src/commonMain/kotlin/app/valenced/plugins/external/ExternalManifest.kt @@ -1,5 +1,6 @@ package app.valenced.plugins.external +import app.valenced.plugins.ContributorSerializer import app.valenced.plugins.PluginDependency import app.valenced.plugins.PluginManifest import app.valenced.plugins.RESERVED_DEPENDENCY_IDS @@ -19,8 +20,9 @@ data class ExternalManifest( val id: String, val name: String, val description: String = "", - val author: String = "", - val contributors: List = emptyList(), + /** Contributor object, or legacy string. See [ContributorSerializer]. */ + @Serializable(with = ContributorSerializer::class) val author: String = "", + val contributors: List<@Serializable(with = ContributorSerializer::class) String> = emptyList(), /* See [validatedPluginIcon]. */ val icon: String? = null, /** The plugin's version. */ diff --git a/core/src/commonMain/kotlin/app/valenced/plugins/repos/RepoIndex.kt b/core/src/commonMain/kotlin/app/valenced/plugins/repos/RepoIndex.kt index d82df05d..edc1383c 100644 --- a/core/src/commonMain/kotlin/app/valenced/plugins/repos/RepoIndex.kt +++ b/core/src/commonMain/kotlin/app/valenced/plugins/repos/RepoIndex.kt @@ -2,6 +2,7 @@ package app.valenced.plugins.repos import app.valenced.core.Logger import app.valenced.core.ValencedJson +import app.valenced.plugins.ContributorSerializer import app.valenced.plugins.Version import app.valenced.plugins.VersionRange import app.valenced.plugins.external.ExternalDependency @@ -29,8 +30,9 @@ data class RepoIndex( data class RepoPlugin( val name: String, val description: String = "", - val author: String = "", - val contributors: List = emptyList(), + /** Contributor object, or legacy string. See [ContributorSerializer]. */ + @Serializable(with = ContributorSerializer::class) val author: String = "", + val contributors: List<@Serializable(with = ContributorSerializer::class) String> = emptyList(), /** A Discord asset name or a `data:` URL. */ val icon: String? = null, /** diff --git a/core/src/commonTest/kotlin/app/valenced/plugins/external/ExternalManifestTest.kt b/core/src/commonTest/kotlin/app/valenced/plugins/external/ExternalManifestTest.kt index 654babbd..644f8994 100644 --- a/core/src/commonTest/kotlin/app/valenced/plugins/external/ExternalManifestTest.kt +++ b/core/src/commonTest/kotlin/app/valenced/plugins/external/ExternalManifestTest.kt @@ -1,5 +1,6 @@ package app.valenced.plugins.external +import app.valenced.core.ValencedJson import app.valenced.plugins.API_DEPENDENCY_ID import app.valenced.plugins.DISCORD_DEPENDENCY_ID import kotlin.test.Test @@ -61,4 +62,27 @@ class ExternalManifestTest { assertNull(manifest(icon = "https://example.test/icon.png").toPluginManifest().icon) assertNull(manifest(icon = "data:image/png;base64," + "A".repeat(128 * 1024)).toPluginManifest().icon) } + + @Test + fun `contributors are strings or objects`() { + val parsed = ValencedJson.decodeFromString( + """ + { + "format": 1, "id": "a.b", "name": "A", "version": "1.0.0", + "author": { + "name": "Jane", + "ids": ["123456789012345678"], + "links": [{ "url": "https://example.com", "title": "Website" }, { "url": "mailto:jane@example.com" }] + }, + "contributors": ["John <876543210987654321>", { "name": "Bob" }] + } + """, + ) + + assertEquals( + "Jane <123456789012345678> (https://example.com \"Website\") (mailto:jane@example.com)", + parsed.author, + ) + assertEquals(listOf("John <876543210987654321>", "Bob"), parsed.contributors) + } } From fca89ddd5b92efcfe2958e840ed4745e0b71e991 Mon Sep 17 00:00:00 2001 From: thororen <78185467+thororen1234@users.noreply.github.com> Date: Thu, 29 Oct 2026 23:32:49 -0400 Subject: [PATCH 2/5] im losing it --- bundle/lib/plugins/src/utils.test.ts | 6 +++--- bundle/lib/plugins/src/utils.ts | 8 ++++---- .../commonMain/kotlin/app/valenced/plugins/Contributor.kt | 8 ++++---- .../app/valenced/plugins/external/ExternalManifestTest.kt | 6 +++--- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/bundle/lib/plugins/src/utils.test.ts b/bundle/lib/plugins/src/utils.test.ts index f35207e4..74cde248 100644 --- a/bundle/lib/plugins/src/utils.test.ts +++ b/bundle/lib/plugins/src/utils.test.ts @@ -77,7 +77,7 @@ describe('formatPluginContributor', () => { test('formats objects into a parseable string', () => { const formatted = formatPluginContributor({ name: 'Jane Doe', - ids: [Id1, Id2], + id: Id1, links: [ { url: 'https://example.com/jane', title: 'Website' }, { url: 'mailto:jane@example.com' }, @@ -85,11 +85,11 @@ describe('formatPluginContributor', () => { }) expect(formatted).toBe( - `Jane Doe <${Id1}> <${Id2}> (https://example.com/jane "Website") (mailto:jane@example.com)`, + `Jane Doe <${Id1}> (https://example.com/jane "Website") (mailto:jane@example.com)`, ) expect(parsePluginContributor(formatted)).toEqual({ name: 'Jane Doe', - ids: [Id1, Id2], + ids: [Id1], links: [ { url: 'https://example.com/jane', label: 'Website' }, { url: 'mailto:jane@example.com', label: undefined }, diff --git a/bundle/lib/plugins/src/utils.ts b/bundle/lib/plugins/src/utils.ts index ddb54c94..c01da264 100644 --- a/bundle/lib/plugins/src/utils.ts +++ b/bundle/lib/plugins/src/utils.ts @@ -25,8 +25,8 @@ export interface PluginContributorLink { */ export interface PluginContributorInput { name: string - /** Discord user IDs. */ - ids?: string[] + /** Discord user ID. */ + id?: string links?: { url: string; title?: string }[] } @@ -36,10 +36,10 @@ export function formatPluginContributor( ): string { if (typeof contributor === 'string') return contributor - const { name, ids = [], links = [] } = contributor + const { name, id, links = [] } = contributor return [ name.trim(), - ...ids.map(id => `<${id}>`), + ...(id === undefined ? [] : [`<${id}>`]), ...links.map(({ url, title }) => title === undefined ? `(${url})` : `(${url} "${title}")`, ), diff --git a/core/src/commonMain/kotlin/app/valenced/plugins/Contributor.kt b/core/src/commonMain/kotlin/app/valenced/plugins/Contributor.kt index c44c2852..a06192ec 100644 --- a/core/src/commonMain/kotlin/app/valenced/plugins/Contributor.kt +++ b/core/src/commonMain/kotlin/app/valenced/plugins/Contributor.kt @@ -10,7 +10,7 @@ import kotlinx.serialization.json.JsonDecoder import kotlinx.serialization.json.JsonPrimitive /** - * Contributor as written in manifests: `{ "name": "...", "ids"?: [""], "links"?: [{ "url": "...", "title"?: "..." }] }`. + * Contributor as written in manifests: `{ "name": "...", "id"?: "", "links"?: [{ "url": "...", "title"?: "..." }] }`. * Preferred over the legacy `Name (LINK "TITLE")` string, which is still accepted. * * Decoded into the string form of [PluginManifest.author]. @@ -18,8 +18,8 @@ import kotlinx.serialization.json.JsonPrimitive @Serializable internal data class ContributorObject( val name: String, - /** Discord user IDs. */ - val ids: List = emptyList(), + /** Discord user ID. */ + val id: String? = null, val links: List = emptyList(), ) { @Serializable @@ -27,7 +27,7 @@ internal data class ContributorObject( fun format() = buildString { append(name.trim()) - for (id in ids) append(" <").append(id).append('>') + if (id != null) append(" <").append(id).append('>') for ((url, title) in links) { append(" (").append(url) if (title != null) append(" \"").append(title).append('"') diff --git a/core/src/commonTest/kotlin/app/valenced/plugins/external/ExternalManifestTest.kt b/core/src/commonTest/kotlin/app/valenced/plugins/external/ExternalManifestTest.kt index 644f8994..0e9c3d1e 100644 --- a/core/src/commonTest/kotlin/app/valenced/plugins/external/ExternalManifestTest.kt +++ b/core/src/commonTest/kotlin/app/valenced/plugins/external/ExternalManifestTest.kt @@ -71,10 +71,10 @@ class ExternalManifestTest { "format": 1, "id": "a.b", "name": "A", "version": "1.0.0", "author": { "name": "Jane", - "ids": ["123456789012345678"], + "id": "123456789012345678", "links": [{ "url": "https://example.com", "title": "Website" }, { "url": "mailto:jane@example.com" }] }, - "contributors": ["John <876543210987654321>", { "name": "Bob" }] + "contributors": ["John <876543210987654321>", { "name": "Bob", "id": "112233445566778899" }] } """, ) @@ -83,6 +83,6 @@ class ExternalManifestTest { "Jane <123456789012345678> (https://example.com \"Website\") (mailto:jane@example.com)", parsed.author, ) - assertEquals(listOf("John <876543210987654321>", "Bob"), parsed.contributors) + assertEquals(listOf("John <876543210987654321>", "Bob <112233445566778899>"), parsed.contributors) } } From 848edb7eef46ff14a09b14595bb8c475238d3e0c Mon Sep 17 00:00:00 2001 From: thororen <78185467+thororen1234@users.noreply.github.com> Date: Thu, 29 Oct 2026 23:38:02 -0400 Subject: [PATCH 3/5] make diff smaller --- .../plugins/internal/BundledPluginsTest.kt | 2 +- bundle/lib/plugins/src/types.ts | 1 - bundle/lib/plugins/src/utils.ts | 12 ++++------ bundle/scripts/manifest.ts | 23 +++++-------------- .../app/valenced/plugins/BundleManifest.kt | 4 ++-- .../app/valenced/plugins/Contributor.kt | 4 +++- .../plugins/external/ExternalManifest.kt | 7 +++--- .../app/valenced/plugins/repos/RepoIndex.kt | 7 +++--- 8 files changed, 23 insertions(+), 37 deletions(-) diff --git a/android/src/test/kotlin/app/valenced/xposed/tweaks/plugins/internal/BundledPluginsTest.kt b/android/src/test/kotlin/app/valenced/xposed/tweaks/plugins/internal/BundledPluginsTest.kt index 65d6f12a..063d975d 100644 --- a/android/src/test/kotlin/app/valenced/xposed/tweaks/plugins/internal/BundledPluginsTest.kt +++ b/android/src/test/kotlin/app/valenced/xposed/tweaks/plugins/internal/BundledPluginsTest.kt @@ -112,7 +112,7 @@ class BundledPluginsTest { "id": "valenced.settings.themes", "name": "Theme Settings", "description": "Manage your themes.", - "author": "Valenced", + "author": { "name": "Valenced" }, "icon": "PaintPaletteIcon", "defaultSource": { "repo": "https://example.com" } } diff --git a/bundle/lib/plugins/src/types.ts b/bundle/lib/plugins/src/types.ts index 38378c2b..0b2365a2 100644 --- a/bundle/lib/plugins/src/types.ts +++ b/bundle/lib/plugins/src/types.ts @@ -140,7 +140,6 @@ export interface PluginManifest { /** * Author information, as `Name (LINK "LABEL")`. * Discord IDs and links are optional and repeatable. - * `manifest.json` should use the object form ({@link PluginContributorInput}) instead, normalized into this string. * * Use {@link getPluginContributorName} and {@link parsePluginContributor} to extract the name, IDs, and links. */ diff --git a/bundle/lib/plugins/src/utils.ts b/bundle/lib/plugins/src/utils.ts index c01da264..dba01318 100644 --- a/bundle/lib/plugins/src/utils.ts +++ b/bundle/lib/plugins/src/utils.ts @@ -37,13 +37,11 @@ export function formatPluginContributor( if (typeof contributor === 'string') return contributor const { name, id, links = [] } = contributor - return [ - name.trim(), - ...(id === undefined ? [] : [`<${id}>`]), - ...links.map(({ url, title }) => - title === undefined ? `(${url})` : `(${url} "${title}")`, - ), - ].join(' ') + let formatted = name.trim() + if (id !== undefined) formatted += ` <${id}>` + for (const { url, title } of links) + formatted += title === undefined ? ` (${url})` : ` (${url} "${title}")` + return formatted } const ContributorEntryRegex = diff --git a/bundle/scripts/manifest.ts b/bundle/scripts/manifest.ts index 04ed3268..cac3ef29 100644 --- a/bundle/scripts/manifest.ts +++ b/bundle/scripts/manifest.ts @@ -2,7 +2,6 @@ import { readdir, readFile } from 'fs/promises' import { dirname } from 'path' import { fileURLToPath } from 'url' import { ReservedDependencyIds } from '../lib/plugins/src/_internal/manifest' -import { formatPluginContributor } from '../lib/plugins/src/utils' import { exists, stringEnv } from './_shared' import type { InternalPluginManifest } from '@valenced/plugins/_' @@ -21,8 +20,8 @@ interface BundleManifestPlugin { // Metadata, stubs only. Native shows a restored stub before JS can fill these in. name?: string description?: string - author?: string - contributors?: string[] + author?: InternalPluginManifest['author'] + contributors?: InternalPluginManifest['contributors'] icon?: string defaultSource?: { repo: string @@ -32,14 +31,8 @@ interface BundleManifestPlugin { } interface RawBundleManifestPlugin - extends Omit< - BundleManifestPlugin, - 'enabledByDefault' | 'defaultSource' | 'author' | 'contributors' - >, - Pick< - InternalPluginManifest, - 'enabledByDefault' | 'defaultSource' | 'author' | 'contributors' - > { + extends Omit, + Pick { build?: { devOnly?: boolean } @@ -121,12 +114,8 @@ export async function getInternalPluginManifests( ...(defaultSource && { name: manifest.name, description: manifest.description, - author: - manifest.author && - formatPluginContributor(manifest.author), - contributors: manifest.contributors?.map( - formatPluginContributor, - ), + author: manifest.author, + contributors: manifest.contributors, icon: manifest.icon, }), ...(manifest.essential && { essential: true }), diff --git a/core/src/commonMain/kotlin/app/valenced/plugins/BundleManifest.kt b/core/src/commonMain/kotlin/app/valenced/plugins/BundleManifest.kt index e94bd815..293cbe44 100644 --- a/core/src/commonMain/kotlin/app/valenced/plugins/BundleManifest.kt +++ b/core/src/commonMain/kotlin/app/valenced/plugins/BundleManifest.kt @@ -26,8 +26,8 @@ data class BundleManifest( // Metadata for stubs only. val name: String? = null, val description: String? = null, - val author: String? = null, - val contributors: List = emptyList(), + val author: Contributor? = null, + val contributors: List = emptyList(), val icon: String? = null, val defaultSource: PluginSource? = null, ) diff --git a/core/src/commonMain/kotlin/app/valenced/plugins/Contributor.kt b/core/src/commonMain/kotlin/app/valenced/plugins/Contributor.kt index a06192ec..3433167c 100644 --- a/core/src/commonMain/kotlin/app/valenced/plugins/Contributor.kt +++ b/core/src/commonMain/kotlin/app/valenced/plugins/Contributor.kt @@ -36,7 +36,9 @@ internal data class ContributorObject( } } -/** Accepts a [ContributorObject] or a legacy contributor string, always decoding to the string form. */ +/** Contributor field: a [ContributorObject] or a legacy string, always decoded to the string form. */ +typealias Contributor = @Serializable(with = ContributorSerializer::class) String + object ContributorSerializer : KSerializer { override val descriptor = PrimitiveSerialDescriptor("app.valenced.plugins.Contributor", PrimitiveKind.STRING) diff --git a/core/src/commonMain/kotlin/app/valenced/plugins/external/ExternalManifest.kt b/core/src/commonMain/kotlin/app/valenced/plugins/external/ExternalManifest.kt index 815999ca..8e8ac800 100644 --- a/core/src/commonMain/kotlin/app/valenced/plugins/external/ExternalManifest.kt +++ b/core/src/commonMain/kotlin/app/valenced/plugins/external/ExternalManifest.kt @@ -1,6 +1,6 @@ package app.valenced.plugins.external -import app.valenced.plugins.ContributorSerializer +import app.valenced.plugins.Contributor import app.valenced.plugins.PluginDependency import app.valenced.plugins.PluginManifest import app.valenced.plugins.RESERVED_DEPENDENCY_IDS @@ -20,9 +20,8 @@ data class ExternalManifest( val id: String, val name: String, val description: String = "", - /** Contributor object, or legacy string. See [ContributorSerializer]. */ - @Serializable(with = ContributorSerializer::class) val author: String = "", - val contributors: List<@Serializable(with = ContributorSerializer::class) String> = emptyList(), + val author: Contributor = "", + val contributors: List = emptyList(), /* See [validatedPluginIcon]. */ val icon: String? = null, /** The plugin's version. */ diff --git a/core/src/commonMain/kotlin/app/valenced/plugins/repos/RepoIndex.kt b/core/src/commonMain/kotlin/app/valenced/plugins/repos/RepoIndex.kt index edc1383c..4ae2ad8e 100644 --- a/core/src/commonMain/kotlin/app/valenced/plugins/repos/RepoIndex.kt +++ b/core/src/commonMain/kotlin/app/valenced/plugins/repos/RepoIndex.kt @@ -2,7 +2,7 @@ package app.valenced.plugins.repos import app.valenced.core.Logger import app.valenced.core.ValencedJson -import app.valenced.plugins.ContributorSerializer +import app.valenced.plugins.Contributor import app.valenced.plugins.Version import app.valenced.plugins.VersionRange import app.valenced.plugins.external.ExternalDependency @@ -30,9 +30,8 @@ data class RepoIndex( data class RepoPlugin( val name: String, val description: String = "", - /** Contributor object, or legacy string. See [ContributorSerializer]. */ - @Serializable(with = ContributorSerializer::class) val author: String = "", - val contributors: List<@Serializable(with = ContributorSerializer::class) String> = emptyList(), + val author: Contributor = "", + val contributors: List = emptyList(), /** A Discord asset name or a `data:` URL. */ val icon: String? = null, /** From 77d29aeac3da18b8dcc48a4cd728746afb151945 Mon Sep 17 00:00:00 2001 From: thororen <78185467+thororen1234@users.noreply.github.com> Date: Fri, 30 Oct 2026 00:49:37 -0400 Subject: [PATCH 4/5] changes --- .../plugins/internal/BundledPluginsTest.kt | 2 +- bundle/scripts/manifest.test.ts | 15 ++++++ bundle/scripts/manifest.ts | 23 +++++--- .../app/valenced/plugins/BundleManifest.kt | 4 +- .../app/valenced/plugins/Contributor.kt | 54 ------------------- .../plugins/external/ExternalManifest.kt | 5 +- .../app/valenced/plugins/repos/RepoIndex.kt | 5 +- .../plugins/external/ExternalManifestTest.kt | 24 --------- 8 files changed, 39 insertions(+), 93 deletions(-) delete mode 100644 core/src/commonMain/kotlin/app/valenced/plugins/Contributor.kt diff --git a/android/src/test/kotlin/app/valenced/xposed/tweaks/plugins/internal/BundledPluginsTest.kt b/android/src/test/kotlin/app/valenced/xposed/tweaks/plugins/internal/BundledPluginsTest.kt index 063d975d..65d6f12a 100644 --- a/android/src/test/kotlin/app/valenced/xposed/tweaks/plugins/internal/BundledPluginsTest.kt +++ b/android/src/test/kotlin/app/valenced/xposed/tweaks/plugins/internal/BundledPluginsTest.kt @@ -112,7 +112,7 @@ class BundledPluginsTest { "id": "valenced.settings.themes", "name": "Theme Settings", "description": "Manage your themes.", - "author": { "name": "Valenced" }, + "author": "Valenced", "icon": "PaintPaletteIcon", "defaultSource": { "repo": "https://example.com" } } diff --git a/bundle/scripts/manifest.test.ts b/bundle/scripts/manifest.test.ts index f3570d91..5726e527 100644 --- a/bundle/scripts/manifest.test.ts +++ b/bundle/scripts/manifest.test.ts @@ -105,6 +105,21 @@ describe('getInternalPluginManifests', () => { }) }) + it('formats stub contributor objects into strings for native', async () => { + await plugin('start', 'settings.themes', { + id: 'valenced.settings.themes', + author: { name: 'Jane', id: '123456789012345678' }, + contributors: ['John', { name: 'Bob' }], + defaultSource: { repo: 'https://example.com' }, + }) + + const [stub] = await getInternalPluginManifests(root) + expect(stub).toMatchObject({ + author: 'Jane <123456789012345678>', + contributors: ['John', 'Bob'], + }) + }) + it('rejects a version on a plugin that is not a stub', async () => { await plugin('start', 'settings', { id: 'valenced.settings', diff --git a/bundle/scripts/manifest.ts b/bundle/scripts/manifest.ts index cac3ef29..04ed3268 100644 --- a/bundle/scripts/manifest.ts +++ b/bundle/scripts/manifest.ts @@ -2,6 +2,7 @@ import { readdir, readFile } from 'fs/promises' import { dirname } from 'path' import { fileURLToPath } from 'url' import { ReservedDependencyIds } from '../lib/plugins/src/_internal/manifest' +import { formatPluginContributor } from '../lib/plugins/src/utils' import { exists, stringEnv } from './_shared' import type { InternalPluginManifest } from '@valenced/plugins/_' @@ -20,8 +21,8 @@ interface BundleManifestPlugin { // Metadata, stubs only. Native shows a restored stub before JS can fill these in. name?: string description?: string - author?: InternalPluginManifest['author'] - contributors?: InternalPluginManifest['contributors'] + author?: string + contributors?: string[] icon?: string defaultSource?: { repo: string @@ -31,8 +32,14 @@ interface BundleManifestPlugin { } interface RawBundleManifestPlugin - extends Omit, - Pick { + extends Omit< + BundleManifestPlugin, + 'enabledByDefault' | 'defaultSource' | 'author' | 'contributors' + >, + Pick< + InternalPluginManifest, + 'enabledByDefault' | 'defaultSource' | 'author' | 'contributors' + > { build?: { devOnly?: boolean } @@ -114,8 +121,12 @@ export async function getInternalPluginManifests( ...(defaultSource && { name: manifest.name, description: manifest.description, - author: manifest.author, - contributors: manifest.contributors, + author: + manifest.author && + formatPluginContributor(manifest.author), + contributors: manifest.contributors?.map( + formatPluginContributor, + ), icon: manifest.icon, }), ...(manifest.essential && { essential: true }), diff --git a/core/src/commonMain/kotlin/app/valenced/plugins/BundleManifest.kt b/core/src/commonMain/kotlin/app/valenced/plugins/BundleManifest.kt index 293cbe44..e94bd815 100644 --- a/core/src/commonMain/kotlin/app/valenced/plugins/BundleManifest.kt +++ b/core/src/commonMain/kotlin/app/valenced/plugins/BundleManifest.kt @@ -26,8 +26,8 @@ data class BundleManifest( // Metadata for stubs only. val name: String? = null, val description: String? = null, - val author: Contributor? = null, - val contributors: List = emptyList(), + val author: String? = null, + val contributors: List = emptyList(), val icon: String? = null, val defaultSource: PluginSource? = null, ) diff --git a/core/src/commonMain/kotlin/app/valenced/plugins/Contributor.kt b/core/src/commonMain/kotlin/app/valenced/plugins/Contributor.kt deleted file mode 100644 index 3433167c..00000000 --- a/core/src/commonMain/kotlin/app/valenced/plugins/Contributor.kt +++ /dev/null @@ -1,54 +0,0 @@ -package app.valenced.plugins - -import kotlinx.serialization.KSerializer -import kotlinx.serialization.Serializable -import kotlinx.serialization.descriptors.PrimitiveKind -import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import kotlinx.serialization.json.JsonDecoder -import kotlinx.serialization.json.JsonPrimitive - -/** - * Contributor as written in manifests: `{ "name": "...", "id"?: "", "links"?: [{ "url": "...", "title"?: "..." }] }`. - * Preferred over the legacy `Name (LINK "TITLE")` string, which is still accepted. - * - * Decoded into the string form of [PluginManifest.author]. - */ -@Serializable -internal data class ContributorObject( - val name: String, - /** Discord user ID. */ - val id: String? = null, - val links: List = emptyList(), -) { - @Serializable - data class Link(val url: String, val title: String? = null) - - fun format() = buildString { - append(name.trim()) - if (id != null) append(" <").append(id).append('>') - for ((url, title) in links) { - append(" (").append(url) - if (title != null) append(" \"").append(title).append('"') - append(')') - } - } -} - -/** Contributor field: a [ContributorObject] or a legacy string, always decoded to the string form. */ -typealias Contributor = @Serializable(with = ContributorSerializer::class) String - -object ContributorSerializer : KSerializer { - override val descriptor = PrimitiveSerialDescriptor("app.valenced.plugins.Contributor", PrimitiveKind.STRING) - - override fun serialize(encoder: Encoder, value: String) = encoder.encodeString(value) - - override fun deserialize(decoder: Decoder): String { - if (decoder !is JsonDecoder) return decoder.decodeString() - - val element = decoder.decodeJsonElement() - if (element is JsonPrimitive && element.isString) return element.content - return decoder.json.decodeFromJsonElement(ContributorObject.serializer(), element).format() - } -} diff --git a/core/src/commonMain/kotlin/app/valenced/plugins/external/ExternalManifest.kt b/core/src/commonMain/kotlin/app/valenced/plugins/external/ExternalManifest.kt index 8e8ac800..c4dd8fdc 100644 --- a/core/src/commonMain/kotlin/app/valenced/plugins/external/ExternalManifest.kt +++ b/core/src/commonMain/kotlin/app/valenced/plugins/external/ExternalManifest.kt @@ -1,6 +1,5 @@ package app.valenced.plugins.external -import app.valenced.plugins.Contributor import app.valenced.plugins.PluginDependency import app.valenced.plugins.PluginManifest import app.valenced.plugins.RESERVED_DEPENDENCY_IDS @@ -20,8 +19,8 @@ data class ExternalManifest( val id: String, val name: String, val description: String = "", - val author: Contributor = "", - val contributors: List = emptyList(), + val author: String = "", + val contributors: List = emptyList(), /* See [validatedPluginIcon]. */ val icon: String? = null, /** The plugin's version. */ diff --git a/core/src/commonMain/kotlin/app/valenced/plugins/repos/RepoIndex.kt b/core/src/commonMain/kotlin/app/valenced/plugins/repos/RepoIndex.kt index 4ae2ad8e..d82df05d 100644 --- a/core/src/commonMain/kotlin/app/valenced/plugins/repos/RepoIndex.kt +++ b/core/src/commonMain/kotlin/app/valenced/plugins/repos/RepoIndex.kt @@ -2,7 +2,6 @@ package app.valenced.plugins.repos import app.valenced.core.Logger import app.valenced.core.ValencedJson -import app.valenced.plugins.Contributor import app.valenced.plugins.Version import app.valenced.plugins.VersionRange import app.valenced.plugins.external.ExternalDependency @@ -30,8 +29,8 @@ data class RepoIndex( data class RepoPlugin( val name: String, val description: String = "", - val author: Contributor = "", - val contributors: List = emptyList(), + val author: String = "", + val contributors: List = emptyList(), /** A Discord asset name or a `data:` URL. */ val icon: String? = null, /** diff --git a/core/src/commonTest/kotlin/app/valenced/plugins/external/ExternalManifestTest.kt b/core/src/commonTest/kotlin/app/valenced/plugins/external/ExternalManifestTest.kt index 0e9c3d1e..654babbd 100644 --- a/core/src/commonTest/kotlin/app/valenced/plugins/external/ExternalManifestTest.kt +++ b/core/src/commonTest/kotlin/app/valenced/plugins/external/ExternalManifestTest.kt @@ -1,6 +1,5 @@ package app.valenced.plugins.external -import app.valenced.core.ValencedJson import app.valenced.plugins.API_DEPENDENCY_ID import app.valenced.plugins.DISCORD_DEPENDENCY_ID import kotlin.test.Test @@ -62,27 +61,4 @@ class ExternalManifestTest { assertNull(manifest(icon = "https://example.test/icon.png").toPluginManifest().icon) assertNull(manifest(icon = "data:image/png;base64," + "A".repeat(128 * 1024)).toPluginManifest().icon) } - - @Test - fun `contributors are strings or objects`() { - val parsed = ValencedJson.decodeFromString( - """ - { - "format": 1, "id": "a.b", "name": "A", "version": "1.0.0", - "author": { - "name": "Jane", - "id": "123456789012345678", - "links": [{ "url": "https://example.com", "title": "Website" }, { "url": "mailto:jane@example.com" }] - }, - "contributors": ["John <876543210987654321>", { "name": "Bob", "id": "112233445566778899" }] - } - """, - ) - - assertEquals( - "Jane <123456789012345678> (https://example.com \"Website\") (mailto:jane@example.com)", - parsed.author, - ) - assertEquals(listOf("John <876543210987654321>", "Bob <112233445566778899>"), parsed.contributors) - } } From e8603fd76c2e6cd68588e42c66a28c8034a86a15 Mon Sep 17 00:00:00 2001 From: thororen <78185467+thororen1234@users.noreply.github.com> Date: Fri, 30 Oct 2026 01:01:16 -0400 Subject: [PATCH 5/5] add support server to manifests --- bundle/src/plugins/preinit/api.hidden/manifest.json | 5 ++++- bundle/src/plugins/preinit/api.themes/manifest.json | 5 ++++- bundle/src/plugins/preinit/api/manifest.json | 5 ++++- bundle/src/plugins/preinit/logging/manifest.json | 5 ++++- bundle/src/plugins/preinit/no-track/manifest.json | 5 ++++- bundle/src/plugins/preinit/recovery/manifest.json | 5 ++++- bundle/src/plugins/start/settings.plugins/manifest.json | 5 ++++- bundle/src/plugins/start/settings.themes/manifest.json | 5 ++++- bundle/src/plugins/start/settings/manifest.json | 5 ++++- bundle/src/plugins/start/staff-settings/manifest.json | 5 ++++- bundle/src/plugins/start/user-badges/manifest.json | 5 ++++- 11 files changed, 44 insertions(+), 11 deletions(-) diff --git a/bundle/src/plugins/preinit/api.hidden/manifest.json b/bundle/src/plugins/preinit/api.hidden/manifest.json index 04465bea..a109542f 100644 --- a/bundle/src/plugins/preinit/api.hidden/manifest.json +++ b/bundle/src/plugins/preinit/api.hidden/manifest.json @@ -2,7 +2,10 @@ "id": "valenced.api.hidden", "name": "Developer Mode", "description": "Exposes internal Valenced APIs for debugging.", - "author": { "name": "Valenced" }, + "author": { + "name": "Valenced", + "links": [{ "url": "https://discord.com/invite/dtBTQHYSx4", "title": "Support Server" }] + }, "icon": "WrenchIcon", "enabledByDefault": "dev" } diff --git a/bundle/src/plugins/preinit/api.themes/manifest.json b/bundle/src/plugins/preinit/api.themes/manifest.json index ef44710a..f0339dcf 100644 --- a/bundle/src/plugins/preinit/api.themes/manifest.json +++ b/bundle/src/plugins/preinit/api.themes/manifest.json @@ -2,7 +2,10 @@ "id": "valenced.api.themes", "name": "Themes API", "description": "This feature requires an update to be installed.", - "author": { "name": "Valenced" }, + "author": { + "name": "Valenced", + "links": [{ "url": "https://discord.com/invite/dtBTQHYSx4", "title": "Support Server" }] + }, "icon": "PaintPaletteIcon", "version": "0.0.0", "enabledByDefault": true, diff --git a/bundle/src/plugins/preinit/api/manifest.json b/bundle/src/plugins/preinit/api/manifest.json index 6ad226f6..8db120a2 100644 --- a/bundle/src/plugins/preinit/api/manifest.json +++ b/bundle/src/plugins/preinit/api/manifest.json @@ -2,7 +2,10 @@ "id": "valenced.api", "name": "Plugin API", "description": "Provides the Valenced plugin API.", - "author": { "name": "Valenced" }, + "author": { + "name": "Valenced", + "links": [{ "url": "https://discord.com/invite/dtBTQHYSx4", "title": "Support Server" }] + }, "icon": "PollsIcon", "essential": true, "api": true diff --git a/bundle/src/plugins/preinit/logging/manifest.json b/bundle/src/plugins/preinit/logging/manifest.json index 87ceb21f..1f999225 100644 --- a/bundle/src/plugins/preinit/logging/manifest.json +++ b/bundle/src/plugins/preinit/logging/manifest.json @@ -2,7 +2,10 @@ "id": "valenced.logging", "name": "Logging", "description": "Logs assisting Valenced developers.", - "author": { "name": "Valenced" }, + "author": { + "name": "Valenced", + "links": [{ "url": "https://discord.com/invite/dtBTQHYSx4", "title": "Support Server" }] + }, "icon": "PaperIcon", "enabledByDefault": true, "build": { diff --git a/bundle/src/plugins/preinit/no-track/manifest.json b/bundle/src/plugins/preinit/no-track/manifest.json index 2353b568..53a8482b 100644 --- a/bundle/src/plugins/preinit/no-track/manifest.json +++ b/bundle/src/plugins/preinit/no-track/manifest.json @@ -2,7 +2,10 @@ "id": "valenced.no-track", "name": "No Track", "description": "Disables Discord and Sentry analytics.", - "author": { "name": "Valenced" }, + "author": { + "name": "Valenced", + "links": [{ "url": "https://discord.com/invite/dtBTQHYSx4", "title": "Support Server" }] + }, "icon": "AnalyticsIcon", "enabledByDefault": true } diff --git a/bundle/src/plugins/preinit/recovery/manifest.json b/bundle/src/plugins/preinit/recovery/manifest.json index 5ceb8551..d3072c23 100644 --- a/bundle/src/plugins/preinit/recovery/manifest.json +++ b/bundle/src/plugins/preinit/recovery/manifest.json @@ -2,7 +2,10 @@ "id": "valenced.recovery", "name": "Recovery", "description": "Handles errors and provides troubleshooting options for Valenced.", - "author": { "name": "Valenced" }, + "author": { + "name": "Valenced", + "links": [{ "url": "https://discord.com/invite/dtBTQHYSx4", "title": "Support Server" }] + }, "icon": "ShieldIcon", "essential": true, "dependencies": { diff --git a/bundle/src/plugins/start/settings.plugins/manifest.json b/bundle/src/plugins/start/settings.plugins/manifest.json index 31ffc7ae..402af9a9 100644 --- a/bundle/src/plugins/start/settings.plugins/manifest.json +++ b/bundle/src/plugins/start/settings.plugins/manifest.json @@ -2,7 +2,10 @@ "id": "valenced.settings.plugins", "name": "Plugin Settings", "description": "Plugin management UI for Valenced.", - "author": { "name": "Valenced" }, + "author": { + "name": "Valenced", + "links": [{ "url": "https://discord.com/invite/dtBTQHYSx4", "title": "Support Server" }] + }, "icon": "PuzzlePieceIcon", "essential": true, "dependencies": { diff --git a/bundle/src/plugins/start/settings.themes/manifest.json b/bundle/src/plugins/start/settings.themes/manifest.json index b61d9aa5..8f1bc99e 100644 --- a/bundle/src/plugins/start/settings.themes/manifest.json +++ b/bundle/src/plugins/start/settings.themes/manifest.json @@ -2,7 +2,10 @@ "id": "valenced.settings.themes", "name": "Themes", "description": "This feature requires an update to be installed.", - "author": { "name": "Valenced" }, + "author": { + "name": "Valenced", + "links": [{ "url": "https://discord.com/invite/dtBTQHYSx4", "title": "Support Server" }] + }, "icon": "PaintPaletteIcon", "version": "0.0.0", "enabledByDefault": true, diff --git a/bundle/src/plugins/start/settings/manifest.json b/bundle/src/plugins/start/settings/manifest.json index a5516bde..f4c240c3 100644 --- a/bundle/src/plugins/start/settings/manifest.json +++ b/bundle/src/plugins/start/settings/manifest.json @@ -2,7 +2,10 @@ "id": "valenced.settings", "name": "Settings", "description": "Settings UI for Valenced.", - "author": { "name": "Valenced" }, + "author": { + "name": "Valenced", + "links": [{ "url": "https://discord.com/invite/dtBTQHYSx4", "title": "Support Server" }] + }, "icon": "SettingsIcon", "essential": true } diff --git a/bundle/src/plugins/start/staff-settings/manifest.json b/bundle/src/plugins/start/staff-settings/manifest.json index aeee8d4c..7a306637 100644 --- a/bundle/src/plugins/start/staff-settings/manifest.json +++ b/bundle/src/plugins/start/staff-settings/manifest.json @@ -2,7 +2,10 @@ "id": "valenced.staff-settings", "name": "Staff Settings", "description": "Allows accessing Discord's Staff Settings.", - "author": { "name": "Valenced" }, + "author": { + "name": "Valenced", + "links": [{ "url": "https://discord.com/invite/dtBTQHYSx4", "title": "Support Server" }] + }, "icon": "StaffBadgeIcon", "enabledByDefault": true } diff --git a/bundle/src/plugins/start/user-badges/manifest.json b/bundle/src/plugins/start/user-badges/manifest.json index 931fe64e..2c04704e 100644 --- a/bundle/src/plugins/start/user-badges/manifest.json +++ b/bundle/src/plugins/start/user-badges/manifest.json @@ -2,7 +2,10 @@ "id": "valenced.user-badges", "name": "User Badges", "description": "Badges for Valenced contributors and sponsors.", - "author": { "name": "Valenced" }, + "author": { + "name": "Valenced", + "links": [{ "url": "https://discord.com/invite/dtBTQHYSx4", "title": "Support Server" }] + }, "icon": "ShieldUserIcon", "essential": true }