Skip to content
This repository was archived by the owner on Jul 28, 2026. It is now read-only.

Add auto widget creation functionality - #2

Draft
DEVKaxtusik wants to merge 1 commit into
mainfrom
auto-widget
Draft

Add auto widget creation functionality#2
DEVKaxtusik wants to merge 1 commit into
mainfrom
auto-widget

Conversation

@DEVKaxtusik

@DEVKaxtusik DEVKaxtusik commented Jul 2, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features
    • Added automatic Discord widget setup and publishing support.
    • Improved Discord API handling so widget settings can be created, updated, and published more reliably.
    • Expanded error logging for failed Discord requests to make issues easier to diagnose.

@DEVKaxtusik DEVKaxtusik self-assigned this Jul 2, 2026
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds Discord widget creation/publishing support to src/providers/discord.ts via a new createWidget() function with isExist() and publishWidget() helpers, a static widget config payload, expanded error logging, a new src/setup.ts entry point invoking createWidget(), and an updated import in src/index.ts.

Changes

Discord widget lifecycle

Layer / File(s) Summary
Discord API client and widget payload
src/providers/discord.ts
Adds a static widgetData configuration payload and updates the discordAPI axios client's Authorization header.
createWidget core logic and helpers
src/providers/discord.ts
Adds exported createWidget() which checks for an existing config via isExist(), PATCHes or POSTs accordingly, and publishes via publishWidget(); both helpers include error logging.
Setup entry point, patchIdentity logging, index import
src/setup.ts, src/providers/discord.ts, src/index.ts
Adds setup.ts loading dotenv and invoking createWidget() on load, expands patchIdentity() error logging with structured status/data, and updates index.ts to import createWidget.

Estimated code review effort: 2 (Simple) | ~12 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Setup
  participant createWidget
  participant isExist
  participant DiscordAPI
  participant publishWidget

  Setup->>createWidget: call createWidget()
  createWidget->>isExist: check existing config
  isExist->>DiscordAPI: GET widget configs
  DiscordAPI-->>isExist: config list or empty
  isExist-->>createWidget: configId or null
  alt config exists
    createWidget->>DiscordAPI: PATCH widget config
  else no config
    createWidget->>DiscordAPI: POST widget config
  end
  createWidget->>publishWidget: publish(configId)
  publishWidget->>DiscordAPI: POST publish endpoint
  DiscordAPI-->>publishWidget: response or error
Loading

Related Issues: None found

Related PRs: None found

Suggested labels: enhancement

Suggested reviewers: DEVKaxtusik

🐰 A widget hops through PATCH and POST,
Publishing configs, checking each host,
Setup awakens with dotenv's grace,
createWidget scurries into place,
A carrot for Discord's new little boast!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: automatic widget creation and related lifecycle support.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch auto-widget

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@DEVKaxtusik
DEVKaxtusik marked this pull request as draft July 2, 2026 16:13

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
src/providers/discord.ts (1)

3-227: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider extracting widgetData into a config/JSON file.

224 lines of static payload embedded in the module hurts readability of the surrounding logic. Not blocking.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/providers/discord.ts` around lines 3 - 227, The `widgetData` object is a
large static payload embedded directly in `src/providers/discord.ts`, making the
module harder to read and maintain. Extract `widgetData` into a separate
config/JSON file and import it back into the provider, keeping only the logic in
the `discord` provider module. Use the `widgetData` symbol as the main target
when moving the data.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/providers/discord.ts`:
- Around line 230-235: The discordAPI axios client is missing a request timeout,
so calls can hang indefinitely; add a timeout to the axios.create configuration
in discordAPI so the client fails fast instead of blocking completion. Update
the existing client setup near discordAPI to include an appropriate timeout
value alongside baseURL and headers, keeping the change localized to the
discordAPI initializer.
- Around line 237-261: The createWidget() flow in src/providers/discord.ts
swallows setup failures by only logging inside the catch block, so the caller
never sees the error and the standalone setup script can still exit
successfully. Update createWidget() to propagate failures after logging by
rethrowing the caught error (or otherwise terminating with a non-zero exit) so
setup.ts can fail the process on bad token, network, or API errors; use
createWidget(), publishWidget(), and the existing discordAPI calls as the key
points to keep behavior intact while making failures visible.
- Around line 263-282: The isExist() helper currently returns null for both “no
widget config exists” and actual fetch failures, so createWidget() can’t tell
whether to create or update. Update isExist() to distinguish these cases by
logging all caught errors (including non-response/network failures) and either
rethrowing or returning a separate failure signal, while preserving null only
for the true “no configs found” path. Then adjust createWidget() to handle that
distinct failure path instead of treating it as an empty result.
- Line 253: The widget config ID handling in the Discord provider is using the
wrong response field, which can leave widgetConfigId unset and break
lookups/publishing. Update the logic in the create/fetch flow around
widgetConfigId, createResponse.data, configs[0], isExist(), and publishWidget()
to read and compare config_id instead of id wherever the widget-config API
response shape is consumed.

---

Nitpick comments:
In `@src/providers/discord.ts`:
- Around line 3-227: The `widgetData` object is a large static payload embedded
directly in `src/providers/discord.ts`, making the module harder to read and
maintain. Extract `widgetData` into a separate config/JSON file and import it
back into the provider, keeping only the logic in the `discord` provider module.
Use the `widgetData` symbol as the main target when moving the data.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 73a00556-67fd-48b3-956b-0bb426d7e2b1

📥 Commits

Reviewing files that changed from the base of the PR and between 671bae6 and 27f7aff.

📒 Files selected for processing (3)
  • src/index.ts
  • src/providers/discord.ts
  • src/setup.ts

Comment thread src/providers/discord.ts
Comment on lines 230 to 235
const discordAPI = axios.create({
baseURL: "https://discord.com/api/v10",
headers: {
"Authorization": "Bot " + process.env.DISCORD_TOKEN!
}
Authorization: "Bot " + process.env.DISCORD_TOKEN!,
},
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

No timeout configured on discordAPI client.

A stalled network call here will hang indefinitely since no timeout is set, which is risky for a script expected to run to completion (e.g. in CI/deploy pipelines).

🕒 Suggested fix
 const discordAPI = axios.create({
   baseURL: "https://discord.com/api/v10",
+  timeout: 10000,
   headers: {
     Authorization: "Bot " + process.env.DISCORD_TOKEN!,
   },
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const discordAPI = axios.create({
baseURL: "https://discord.com/api/v10",
headers: {
"Authorization": "Bot " + process.env.DISCORD_TOKEN!
}
Authorization: "Bot " + process.env.DISCORD_TOKEN!,
},
});
const discordAPI = axios.create({
baseURL: "https://discord.com/api/v10",
timeout: 10000,
headers: {
Authorization: "Bot " + process.env.DISCORD_TOKEN!,
},
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/providers/discord.ts` around lines 230 - 235, The discordAPI axios client
is missing a request timeout, so calls can hang indefinitely; add a timeout to
the axios.create configuration in discordAPI so the client fails fast instead of
blocking completion. Update the existing client setup near discordAPI to include
an appropriate timeout value alongside baseURL and headers, keeping the change
localized to the discordAPI initializer.

Comment thread src/providers/discord.ts
Comment on lines +237 to +261
export async function createWidget() {
let widgetConfigId = await isExist();

try {
if (widgetConfigId) {
console.log(`Updating existing widget config: ${widgetConfigId}`);
await discordAPI.patch(
`/applications/${discordApplicationId}/widget-configs/${widgetConfigId}`,
widgetData,
);
} else {
console.log("No existing config found. Creating a new one...");
const createResponse = await discordAPI.post(
`/applications/${discordApplicationId}/widget-configs`,
widgetData,
);
widgetConfigId = createResponse.data.id;
}

await publishWidget(widgetConfigId!);
console.log(`Successfully published widget configuration: ${widgetConfigId}`);
} catch (error: any) {
console.error("Error setting up/publishing widget: ", error?.response?.data || error.message);
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

createWidget() swallows all failures without signaling failure to the caller.

The catch block only logs and never rethrows or exits non-zero. Since this is invoked from setup.ts as a standalone setup script with no additional error handling, a total failure (bad token, network error, API rejection) will still make the process exit successfully (code 0), silently hiding the failure from any CI/deploy pipeline that checks the exit code.

🚨 Suggested fix
   } catch (error: any) {
     console.error("Error setting up/publishing widget: ", error?.response?.data || error.message);
+    throw error;
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export async function createWidget() {
let widgetConfigId = await isExist();
try {
if (widgetConfigId) {
console.log(`Updating existing widget config: ${widgetConfigId}`);
await discordAPI.patch(
`/applications/${discordApplicationId}/widget-configs/${widgetConfigId}`,
widgetData,
);
} else {
console.log("No existing config found. Creating a new one...");
const createResponse = await discordAPI.post(
`/applications/${discordApplicationId}/widget-configs`,
widgetData,
);
widgetConfigId = createResponse.data.id;
}
await publishWidget(widgetConfigId!);
console.log(`Successfully published widget configuration: ${widgetConfigId}`);
} catch (error: any) {
console.error("Error setting up/publishing widget: ", error?.response?.data || error.message);
}
}
export async function createWidget() {
let widgetConfigId = await isExist();
try {
if (widgetConfigId) {
console.log(`Updating existing widget config: ${widgetConfigId}`);
await discordAPI.patch(
`/applications/${discordApplicationId}/widget-configs/${widgetConfigId}`,
widgetData,
);
} else {
console.log("No existing config found. Creating a new one...");
const createResponse = await discordAPI.post(
`/applications/${discordApplicationId}/widget-configs`,
widgetData,
);
widgetConfigId = createResponse.data.id;
}
await publishWidget(widgetConfigId!);
console.log(`Successfully published widget configuration: ${widgetConfigId}`);
} catch (error: any) {
console.error("Error setting up/publishing widget: ", error?.response?.data || error.message);
throw error;
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/providers/discord.ts` around lines 237 - 261, The createWidget() flow in
src/providers/discord.ts swallows setup failures by only logging inside the
catch block, so the caller never sees the error and the standalone setup script
can still exit successfully. Update createWidget() to propagate failures after
logging by rethrowing the caught error (or otherwise terminating with a non-zero
exit) so setup.ts can fail the process on bad token, network, or API errors; use
createWidget(), publishWidget(), and the existing discordAPI calls as the key
points to keep behavior intact while making failures visible.

Comment thread src/providers/discord.ts
`/applications/${discordApplicationId}/widget-configs`,
widgetData,
);
widgetConfigId = createResponse.data.id;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

What is the exact JSON response shape (field names) for Discord's POST /applications/{application.id}/widget-configs and GET /applications/{application.id}/widget-configs endpoints?

💡 Result:

The endpoints POST /applications/{application.id}/widget-configs and GET /applications/{application.id}/widget-configs relate to the management of application-specific widget configurations, a feature distinct from legacy Guild Widgets [1]. According to documentation for this resource, the widget configuration object uses the following primary fields [1]: - display_name (string): The display name of the widget configuration. - surfaces (map): A collection of widget surfaces, mapped by surface type [1]. When creating a new configuration via POST, the request body accepts the display_name and surfaces fields [1]. The response for both the creation (POST) and retrieval (GET) of these configurations returns the widget configuration object, which typically includes the above fields along with a unique identifier (often config_id) [1][2]. Note: These endpoints are distinct from Guild Widget settings, which involve fields like channel_id and enabled [3][4][5][6]. The application widget config feature is specifically designed for application-level integrations [1].

Citations:


🏁 Script executed:

sed -n '220,290p' src/providers/discord.ts

Repository: DEVKaxtusik/osu-widget

Length of output: 2109


🏁 Script executed:

rg -n "widget-configs|config_id|createResponse\.data\.id|configs\[0\]\.id" src README.md .github docs

Repository: DEVKaxtusik/osu-widget

Length of output: 793


🌐 Web query:

Discord application widget-configs POST GET response schema config_id id widget-configs

💡 Result:

In the context of the Discord API, widget-configs refer to configurations for application widgets displayed on user profiles [1]. These are managed via endpoints associated with an application [1]. Widget Config Object Structure A widget config object typically contains the following fields [1]: - application_id (snowflake): The ID of the application [1]. - config_id (snowflake): The unique ID of the widget configuration [1]. - display_name (string): The user-defined name for the configuration [1]. - surfaces (map): A mapping of surface types (e.g., widget_top, widget_bottom) to their respective layouts and components [2][1]. - status (string): The current status of the configuration [1]. - resolved_assets (array): Optional resolved assets for the widget [1]. - published_at (ISO8601 timestamp): The time the configuration was published [1]. - updated_at (ISO8601 timestamp): The time the configuration was last updated [1]. API Endpoints - Create Application Widget Config: POST /applications/{application.id}/widget-configs [1]. This endpoint requires a payload specifying the display_name and surfaces [1]. - List Application Widget Configs: GET /applications/{application.id}/widget-configs [1]. - Get Developer Application Widget Configs: GET /widget-configs/developer [1]. This allows developers to retrieve configs for applications they have access to [1]. Note: These endpoints are generally considered internal or experimental and are not documented in the official public Discord Developer Portal [3][4][5]. They have been observed through community research and unofficial documentation [1][6]. Developers working with these should be aware that they are subject to change and may require specific experiments or flags to function [6].

Citations:


🌐 Web query:

"POST /applications/{application.id}/widget-configs" "GET /applications/{application.id}/widget-configs" config_id response

💡 Result:

The API pattern POST /applications/{application.id}/widget-configs and GET /applications/{application.id}/widget-configs is commonly used to manage widget configurations for an application [1]. In this architectural pattern: 1. POST /applications/{application.id}/widget-configs: This endpoint is used to create a new widget configuration [1]. Upon successful creation, the API typically returns the newly created widget configuration object in the response body [1]. This response object contains a unique identifier, often referred to as config_id, which can be used for subsequent operations such as publishing or updating the configuration [1][2]. 2. GET /applications/{application.id}/widget-configs: This endpoint is used to retrieve a list of all widget configurations associated with the specified application [1]. The response typically returns an array of widget configuration objects, each containing its respective config_id [1]. While the specific naming conventions and fields (such as config_id versus id) can vary depending on the implementation and service provider, the pattern of returning the created configuration record—including its unique identifier—within the POST response is a standard RESTful practice for resource management [1][2][3]. Developers should refer to the specific API documentation for their service to confirm whether the field is explicitly named config_id or simply id [1][4][5].

Citations:


Use config_id instead of id for widget config IDs.
createResponse.data.id and configs[0].id don’t match the widget-config response shape; if the API returns config_id, widgetConfigId stays empty, isExist() never finds an existing config, and publishWidget() can be called with undefined.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/providers/discord.ts` at line 253, The widget config ID handling in the
Discord provider is using the wrong response field, which can leave
widgetConfigId unset and break lookups/publishing. Update the logic in the
create/fetch flow around widgetConfigId, createResponse.data, configs[0],
isExist(), and publishWidget() to read and compare config_id instead of id
wherever the widget-config API response shape is consumed.

Comment thread src/providers/discord.ts
Comment on lines +263 to +282
async function isExist(): Promise<string | null> {
try {
const response = await discordAPI.get(
`/applications/${discordApplicationId}/widget-configs`,
);

const configs = response.data;

if (configs && configs.length > 0) {
return configs[0].id;
}

return null;
} catch (error: any) {
if (error.response) {
console.error(`ERROR Fetching widget configs:`, JSON.stringify(error.response.data));
}
return null;
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

isExist() conflates "no config exists" with "fetch failed".

Any error without a .response property (network error, timeout, DNS failure) is silently swallowed with no logging at all, and every error path returns null — the same value used to mean "no widget config exists yet". This makes createWidget() unable to distinguish a real absence of config from a transient failure, risking creation of a duplicate widget config (via POST) on every retry after a network blip, instead of updating the existing one.

🛠️ Suggested fix
   } catch (error: any) {
-    if (error.response) {
-      console.error(`ERROR Fetching widget configs:`, JSON.stringify(error.response.data));
-    }
-    return null;
+    console.error(`ERROR Fetching widget configs:`, error.response ? JSON.stringify(error.response.data) : error.message);
+    throw error;
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async function isExist(): Promise<string | null> {
try {
const response = await discordAPI.get(
`/applications/${discordApplicationId}/widget-configs`,
);
const configs = response.data;
if (configs && configs.length > 0) {
return configs[0].id;
}
return null;
} catch (error: any) {
if (error.response) {
console.error(`ERROR Fetching widget configs:`, JSON.stringify(error.response.data));
}
return null;
}
}
async function isExist(): Promise<string | null> {
try {
const response = await discordAPI.get(
`/applications/${discordApplicationId}/widget-configs`,
);
const configs = response.data;
if (configs && configs.length > 0) {
return configs[0].id;
}
return null;
} catch (error: any) {
console.error(
`ERROR Fetching widget configs:`,
error.response ? JSON.stringify(error.response.data) : error.message,
);
throw error;
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/providers/discord.ts` around lines 263 - 282, The isExist() helper
currently returns null for both “no widget config exists” and actual fetch
failures, so createWidget() can’t tell whether to create or update. Update
isExist() to distinguish these cases by logging all caught errors (including
non-response/network failures) and either rethrowing or returning a separate
failure signal, while preserving null only for the true “no configs found” path.
Then adjust createWidget() to handle that distinct failure path instead of
treating it as an empty result.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant