-
-
Notifications
You must be signed in to change notification settings - Fork 2
Add new social media poster plugin #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
🦋 Changeset detectedLatest commit: d3aa44f The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
WalkthroughThis pull request adds a new package, Changes
Suggested Reviewers
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
commit: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (19)
packages/studiocms_socialposter/LICENSE (1)
3-3: Update copyright year to current year.The copyright year is set to 2025, but the current year is 2024. Consider updating it to reflect the current year or use a range (e.g., "2024-2025").
-Copyright (c) 2025 StudioCMS - Adam Matthiesen, Jacob Jenkins, Paul Valladares +Copyright (c) 2024 StudioCMS - Adam Matthiesen, Jacob Jenkins, Paul Valladarespackages/studiocms_socialposter/src/utils/response.ts (1)
1-7: Consider accepting JSON objects instead of strings.The response utility function works as implemented, but it would be more flexible to accept any JSON-serializable object and handle the stringification internally.
-export const response = (status: number, data: string) => +export const response = (status: number, data: unknown) => new Response(data, { status, headers: { 'Content-Type': 'application/json', }, });This would require callers to stringify their JSON before passing it to this function. A more flexible approach:
-export const response = (status: number, data: string) => +export const response = (status: number, data: unknown) => - new Response(data, { + new Response(typeof data === 'string' ? data : JSON.stringify(data), { status, headers: { 'Content-Type': 'application/json', }, });packages/studiocms_socialposter/.gitignore (1)
1-23: Minor formatting improvements for .gitignore file.The .gitignore file contains appropriate entries for a Node.js/TypeScript project, but has two minor formatting issues:
- Line 1 is an unnecessary empty line
- File is missing a newline at the end (EOF newline)
- # generated types .astro/ # dependencies node_modules/ # logs npm-debug.log* yarn-debug.log* yarn-error.log* pnpm-debug.log* # environment variables .env .env.production # macOS-specific files .DS_Store .npmrc -dist/ +dist/ +packages/studiocms_socialposter/src/utils/astroEnvConfig.ts (1)
4-12: Well-structured utility function for environment configurationThe
addAstroEnvConfigutility function is well-defined using the astro-integration-kit'sdefineUtilityand properly hooks into Astro's config setup hook. The function correctly updates the Astro config with environment variables.Consider adding more detailed JSDoc comments explaining what specific environment variables are expected to be in the config and how they relate to the social media platforms.
/** * Add Astro Environment Variables Config for using 'astro:env' + * + * This utility ensures that environment variables for social media platforms + * (Twitter/X, Bluesky, Threads/Instagram) are available in the Astro configuration. */packages/studiocms_socialposter/README.md (1)
5-24: Comprehensive environment variables documentationThe requirements section clearly lists all necessary environment variables for each supported social media platform, making it easy for users to understand what credentials they need.
Fix the grammatical issue in line 7:
- Depending on which services you are trying to post on you may require one of more of the following variables in your `.env` + Depending on which services you are trying to post on, you may require one or more of the following variables in your `.env`🧰 Tools
🪛 LanguageTool
[uncategorized] ~7-~7: Possible missing comma found.
Context: ...n which services you are trying to post on you may require one of more of the foll...(AI_HYDRA_LEO_MISSING_COMMA)
[uncategorized] ~7-~7: “of” seems less likely than “or” (‘either … or’).
Context: ...e trying to post on you may require one of more of the following variables in your...(AI_HYDRA_LEO_CP_OF_OR)
packages/studiocms_socialposter/astroenv.d.ts (1)
1-11: Environment variables declarations look good, consider adding JSDoc comments.The type declarations for the environment variables are well-structured and properly typed as
string | undefined. The organization by platform (Twitter, BlueSky, Threads) makes the file easy to read and maintain.Consider adding JSDoc comments to explain what each credential is used for and any specific requirements, which would help other developers understand their purpose without having to reference external documentation.
declare module 'astro:env/server' { + /** Twitter API key from developer portal */ export const TWITTER_API_KEY: string | undefined; + /** Twitter API secret from developer portal */ export const TWITTER_API_SECRET: string | undefined; + /** Twitter access token for posting */ export const TWITTER_ACCESS_TOKEN: string | undefined; + /** Twitter access secret for posting */ export const TWITTER_ACCESS_SECRET: string | undefined; + /** BlueSky service URL (e.g., https://bsky.social) */ export const BLUESKY_SERVICE: string | undefined; + /** BlueSky account username */ export const BLUESKY_USERNAME: string | undefined; + /** BlueSky account password */ export const BLUESKY_PASSWORD: string | undefined; + /** Threads user ID */ export const THREADS_USER_ID: string | undefined; + /** Threads access token for API authentication */ export const THREADS_ACCESS_TOKEN: string | undefined; }packages/studiocms_socialposter/src/routes/postToTwitter.ts (2)
25-29: Use HTTP 400 for client validation errors.For validation errors like empty content, HTTP status code 400 (Bad Request) would be more appropriate than 500 (Internal Server Error), as this is a client-side issue, not a server failure.
if (!content) { - return response(500, JSON.stringify({ error: 'Content must not be empty' })); + return response(400, JSON.stringify({ error: 'Content must not be empty' })); }
31-45: Add validation for Twitter's character limit.Twitter has a 280 character limit for tweets. Consider adding validation to check the content length before attempting to post, to provide better error feedback to users.
try { + // Check Twitter character limit + if (content.length > 280) { + return response(400, JSON.stringify({ + error: 'Content exceeds Twitter\'s 280 character limit' + })); + } + // Create the tweet await client.v2.tweet(content);packages/studiocms_socialposter/src/routes/postToBlueSky.ts (1)
16-23: Use HTTP 400 for client validation errors.For validation errors like empty content, HTTP status code 400 (Bad Request) would be more appropriate than 500 (Internal Server Error), as this is a client-side issue, not a server failure.
if (!content) { return response( - 500, + 400, JSON.stringify({ error: "Content must not be empty" }), ); }packages/studiocms_socialposter/src/routes/postToThreads.ts (3)
5-14: Improve validation with appropriate HTTP status codes.The route correctly validates environment variables and content, but should use HTTP 400 for client-side validation errors like empty content.
if (!content) { - return response(500, JSON.stringify({ error: 'Content must not be empty' })); + return response(400, JSON.stringify({ error: 'Content must not be empty' })); }
16-57: Use logger instead of console statements.The code uses
console.logfor debugging purposes. For consistency with other routes, consider using theloggermodule imported from 'studiocms:logger' instead.+import logger from 'studiocms:logger'; // ... try { - console.log('Creating Threads post container...'); + logger.info('Creating Threads post container...'); // ... - console.log('Create response:', createResponseData); + logger.info('Create response:', createResponseData); // ... - console.log('Publishing Threads post...'); + logger.info('Publishing Threads post...'); // ... - console.log('Publish response:', publishResponseData); + logger.info('Publish response:', publishResponseData);
58-58: Format success response consistently with other routes.The success response should be formatted as an object with a message property for consistency with the other route handlers.
- return response(200, JSON.stringify('Successfully sent Threads message')); + return response(200, JSON.stringify({ message: 'Successfully sent Threads message' }));packages/studiocms_socialposter/package.json (1)
31-35: Validate tree-shaking behavior.Setting
"sideEffects": falseis helpful for tree-shaking. Confirm that no global side effects—such as polyfills, environment variable manipulations, or side-effectful imports—are needed at runtime. Otherwise, consider settingsideEffectsto an array that names only the truly side-effectful files.packages/studiocms_socialposter/src/pages/socials.astro (2)
34-38: Address TODO comment.There's a TODO to show existing page content for post creation. Consider whether retrieving partial text or excerpt from pages would enhance user experience. You can create a new issue or add it to your backlog for future enhancement.
72-189: Streamline the Counter class.The
updateBSky,updateThreads, andupdateTwittermethods have nearly identical logic. You could centralize this logic (e.g., a single updateLimit method) to reduce code duplication and maintain a consistent approach for any new platforms in the future.packages/studiocms_socialposter/ui.d.ts (4)
60-106: Optionally add error handling for invalid modal IDs
Consider adding safety checks or throwing an error if the modal’s HTML element cannot be found. This prevents silent failures.
108-154: Clarify the jQuery-like doc references
Your documentation says "A jQuery-like function." If you aren’t using jQuery, consider rewording to avoid confusion.
169-200: Potentially unify SingleSidebarHelper with DoubleSidebarHelper
Both helpers deal with showing/hiding sidebars. It might be simpler to refactor them into a single, configurable class if they share significant logic.
202-235: DoubleSidebarHelper architecture
Managing two sidebars simultaneously can grow complex. Consider whether a more centralized approach would reduce code duplication.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (20)
.changeset/every-seas-judge.md(1 hunks).vscode/settings.json(2 hunks)packages/studiocms_socialposter/.gitignore(1 hunks)packages/studiocms_socialposter/LICENSE(1 hunks)packages/studiocms_socialposter/README.md(1 hunks)packages/studiocms_socialposter/astroenv.d.ts(1 hunks)packages/studiocms_socialposter/package.json(1 hunks)packages/studiocms_socialposter/src/index.ts(1 hunks)packages/studiocms_socialposter/src/pages/socials.astro(1 hunks)packages/studiocms_socialposter/src/routes/postToBlueSky.ts(1 hunks)packages/studiocms_socialposter/src/routes/postToThreads.ts(1 hunks)packages/studiocms_socialposter/src/routes/postToTwitter.ts(1 hunks)packages/studiocms_socialposter/src/utils/astroEnvConfig.ts(1 hunks)packages/studiocms_socialposter/src/utils/response.ts(1 hunks)packages/studiocms_socialposter/src/virtuals.d.ts(1 hunks)packages/studiocms_socialposter/tsconfig.json(1 hunks)packages/studiocms_socialposter/ui.d.ts(1 hunks)playground/package.json(1 hunks)playground/studiocms.config.mjs(1 hunks)pnpm-workspace.yaml(1 hunks)
🧰 Additional context used
🧬 Code Definitions (3)
packages/studiocms_socialposter/src/routes/postToTwitter.ts (2)
packages/studiocms_socialposter/astroenv.d.ts (4)
TWITTER_API_KEY(2-2)TWITTER_API_SECRET(3-3)TWITTER_ACCESS_TOKEN(4-4)TWITTER_ACCESS_SECRET(5-5)packages/studiocms_socialposter/src/utils/response.ts (1)
response(1-7)
packages/studiocms_socialposter/src/index.ts (1)
packages/studiocms_socialposter/src/utils/astroEnvConfig.ts (1)
addAstroEnvConfig(7-12)
packages/studiocms_socialposter/src/routes/postToThreads.ts (2)
packages/studiocms_socialposter/astroenv.d.ts (2)
THREADS_ACCESS_TOKEN(10-10)THREADS_USER_ID(9-9)packages/studiocms_socialposter/src/utils/response.ts (1)
response(1-7)
🪛 LanguageTool
packages/studiocms_socialposter/README.md
[uncategorized] ~7-~7: Possible missing comma found.
Context: ...n which services you are trying to post on you may require one of more of the foll...
(AI_HYDRA_LEO_MISSING_COMMA)
[uncategorized] ~7-~7: “of” seems less likely than “or” (‘either … or’).
Context: ...e trying to post on you may require one of more of the following variables in your...
(AI_HYDRA_LEO_CP_OF_OR)
🔇 Additional comments (27)
.changeset/every-seas-judge.md (1)
1-6: Changeset looks good.Properly formatted changeset file for the initial release of the
@studiocms/socialposterpackage.playground/package.json (1)
28-28: Dependency addition looks good.Correctly added the
@studiocms/socialposterpackage as a workspace dependency..vscode/settings.json (1)
7-8: Appropriate additions to spell checker dictionary.The new words added to the cSpell dictionary are all relevant to the social media poster plugin and will prevent false spell-check errors during development.
Also applies to: 11-11, 25-25, 30-30
packages/studiocms_socialposter/src/virtuals.d.ts (1)
1-4: Virtual module declaration looks good.This module declaration correctly sets up a virtual module for the socialposter configuration, which can be imported throughout the application. The typing is properly imported from the index file.
packages/studiocms_socialposter/tsconfig.json (1)
1-9: TypeScript configuration is properly set up.The tsconfig.json file follows best practices for a TypeScript package:
- Extends the base configuration for consistency
- Properly configures output directory to ./dist
- Only emits declaration files which is appropriate for packages built with other tools
- Correctly sets the root directory to ./src
playground/studiocms.config.mjs (2)
4-4: New import for social poster plugin added correctlyThe import statement for the socialPoster plugin is properly added, which is necessary for using the new social media posting functionality.
10-15: Social poster plugin integrated with all platforms enabledThe socialPoster plugin is correctly added to the plugins array with all supported platforms (bluesky, threads, and twitter) enabled. This configuration allows users to post to all three social media platforms from the StudioCMS dashboard.
You might want to verify if enabling all platforms by default is the intended behavior, or if they should be disabled by default as shown in the README example (lines 38-40).
packages/studiocms_socialposter/src/utils/astroEnvConfig.ts (1)
1-3: Proper imports with type safetyThe imports are correctly defined with proper type safety for Astro configuration objects.
packages/studiocms_socialposter/README.md (3)
1-4: Clear and concise plugin introductionThe README starts with a clear title and description, effectively communicating the plugin's purpose.
26-44: Clear usage instructions with exampleThe usage section provides clear instructions with a practical example of how to integrate the plugin into the StudioCMS configuration.
There's a discrepancy between the example in the README (which shows all social platforms set to
falseby default) and the actual implementation in studiocms.config.mjs (which sets all platforms totrue). Verify which is the intended default configuration.
46-48: License information includedThe license information is correctly included, referencing the LICENSE file.
pnpm-workspace.yaml (1)
5-6: Version updates for consistencyThe package versions have been updated from beta.13 to beta.14 consistently across all related packages, maintaining compatibility throughout the workspace.
Also applies to: 11-11, 18-18
packages/studiocms_socialposter/src/routes/postToTwitter.ts (2)
12-15: Environment variables validation looks good.The validation ensures all required Twitter API credentials are present before attempting to use them. This is a good practice to prevent runtime errors.
17-23: Client initialization looks correct.The Twitter client is properly initialized with all the required credentials from environment variables.
packages/studiocms_socialposter/src/routes/postToBlueSky.ts (3)
11-14: Environment variables validation looks good.The validation ensures all required BlueSky credentials are present before attempting to use them.
25-28: Good use of URL constructor for validation.Using the URL constructor ensures that the service URL is valid before making requests.
29-44: Authentication and posting implementation looks good.The login process and post creation are implemented correctly, with the timestamp being set to the current time.
packages/studiocms_socialposter/package.json (2)
1-3:Details
✅ Verification successful
Confirm package metadata consistency.
The package name and version look appropriate for an experimental release. Please ensure any dependent repos or documentation accurately reflect this naming and version to reduce confusion.
🏁 Script executed:
#!/bin/bash # Description: Searching usage references of the package name / version to ensure consistency in the repo. rg -A3 "@studiocms/socialposter"Length of output: 1686
Metadata Consistency Confirmed
After reviewing the repository references, we can confirm that the package metadata for
@studiocms/socialposteris consistent across the codebase. The package name and version (0.1.0-experimental.0) appear correctly in all pertinent files (e.g.,packages/studiocms_socialposter/package.json,pnpm-lock.yaml, playground references, etc.). Please ensure that any external documentation or dependent repository configurations are updated accordingly.
48-63:Details
❓ Verification inconclusive
Verify catalog-based dependency resolution.
The
"catalog:"placeholders in dependencies and peerDependencies may require a custom resolution or registry. Ensure your build scripts and CI environments support these placeholders. If they’re unused or experimental, confirm that normal npm or pnpm registry flows won't break unexpectedly.
🏁 Script executed:
#!/bin/bash # Description: Search references for "catalog:" in the repo to verify their usage or presence. rg "catalog:"Length of output: 2300
Confirm Catalog-Based Dependency Resolution in Build and CI Environments
We verified that the repository consistently uses
"catalog:"(and"catalog:min") placeholders across several files (e.g., in multiplepackage.jsonfiles,pnpm-workspace.yaml, andpnpm-lock.yaml). This confirms that a custom dependency resolution mechanism is in place. However, please ensure that:
- Your build scripts and CI environments are fully configured to recognize and correctly resolve these catalog-based dependencies.
- If these placeholders are experimental or not yet broadly adopted, verify under various conditions that standard npm or pnpm flows are not adversely affected.
packages/studiocms_socialposter/src/index.ts (3)
15-25: Validate default options.Merging user-supplied options with
defaultOptionsis a great approach. Ensure the final plugin behavior is intuitive when users opt out of certain platforms (e.g., confirm no routes or environment variables for disabled services).
61-115: Robust environment schema checks.Your environment variable schema correctly marks variables as optional if the user disables a platform. This is a good practice. Ensure that devs receive a clear error if they enable a platform but forget the associated environment variables.
115-145: Route injection looks solid.Conditionally injecting routes for each platform based on the options is a clear design. This prevents dead routes when a platform is disabled. No further concerns here.
packages/studiocms_socialposter/ui.d.ts (5)
1-4: No issues found in version module
Everything looks correct for the version declaration.
6-9: CSS declaration modules
Good to see dedicated placeholders for global and custom CSS. No issues here.
156-167: Progress helper logic is well-defined
The methods for managing progress bars are consistent and straightforward.
238-292: Reflection on theme toggling
Your theme toggling approach and mutation handling appear robust. For older or special browsers without MutationObserver, consider a fallback if needed.
10-58:Details
❓ Verification inconclusive
Verify existence of listed Astro components
This block references a wide set of Astro component imports and re-exports. Please ensure each of these file paths actually exists in the repository.
🏁 Script executed:
#!/bin/bash # Searching for each relevant .astro file to confirm they exist rg --files | grep 'Button.astro\|Divider.astro\|Input.astro\|Row.astro\|Center.astro\|Textarea.astro\|Checkbox.astro\|Toggle.astro\|RadioGroup.astro\|Toast/Toaster.astro\|Card.astro\|Modal.astro\|Select.astro\|SearchSelect.astro\|Dropdown.astro\|User.astro\|ThemeToggle.astro\|Tabs.astro\|TabItem.astro\|Accordion.astro\|Item.astro\|Footer.astro\|Progress.astro\|Sidebar/Single.astro\|Sidebar/Double.astro\|Breadcrumbs/Breadcrumbs.astro\|Group.astro\|Badge.astro\|Icon/Icon.astro\|Icon/IconBase.astro'Length of output: 503
Action Required: Manual Verification of Astro Component Files
Our automated script did not yield any results for the expected Astro component file paths. Please ensure that each file referenced in the module declarations exists in the repository relative to the root (e.g.,@studiocms/ui/components/Button/Button.astro,@studiocms/ui/components/Divider/Divider.astro, etc.). The absence of automated matches could indicate that these files are missing, have been renamed, or are located in different directories. We recommend manually verifying the existence and correct paths of these components in the repository.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
dreyfus92
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so clean, good, and simple to be true 😭
well... 75% of the actual logic is handled by StudioCMS now... (creating the page, and adding it to the dashboard) then its just fill in the components where ya need them, setup api routes, profit 🤣 |
96e27bb
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (4)
packages/studiocms_socialposter/src/routes/postToTwitter.ts (2)
18-20: Consider using 403 or 401 for unauthorized responses instead of 400.
Technically, returning HTTP 400 indicates a "Bad Request," while 401 or 403 is more specific for unauthorized/forbidden access.-if (!isEditor) { - return response(400, 'Unauthorized'); +if (!isEditor) { + return response(403, JSON.stringify({ error: 'Forbidden' })); }
36-38: Use a 400 status code for invalid or missing request content.
Content validation failures are typically client-side errors (400), not server-side errors (500).-if (!content) { - return response(500, JSON.stringify({ error: 'Content must not be empty' })); +if (!content) { + return response(400, JSON.stringify({ error: 'Content must not be empty' })); }packages/studiocms_socialposter/src/routes/postToBlueSky.ts (2)
13-15: Use a more suitable status code for unauthorized access.
Similar to the Twitter route, use 403 or 401 rather than 400 to better align with HTTP specification.-if (!isEditor) { - return response(400, 'Unauthorized'); +if (!isEditor) { + return response(403, JSON.stringify({ error: 'Forbidden' })); }
23-25: Return 400 for missing content instead of 500.
Empty content is usually a client error, so a 400 status better reflects the issue’s origin.-if (!content) { - return response(500, JSON.stringify({ error: 'Content must not be empty' })); +if (!content) { + return response(400, JSON.stringify({ error: 'Content must not be empty' })); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
packages/studiocms_socialposter/src/routes/postToBlueSky.ts(1 hunks)packages/studiocms_socialposter/src/routes/postToThreads.ts(1 hunks)packages/studiocms_socialposter/src/routes/postToTwitter.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/studiocms_socialposter/src/routes/postToThreads.ts
🧰 Additional context used
🧬 Code Definitions (2)
packages/studiocms_socialposter/src/routes/postToTwitter.ts (2)
packages/studiocms_socialposter/src/utils/response.ts (1)
response(1-7)packages/studiocms_socialposter/astroenv.d.ts (4)
TWITTER_API_KEY(2-2)TWITTER_API_SECRET(3-3)TWITTER_ACCESS_TOKEN(4-4)TWITTER_ACCESS_SECRET(5-5)
packages/studiocms_socialposter/src/routes/postToBlueSky.ts (4)
packages/studiocms_socialposter/src/routes/postToTwitter.ts (1)
POST(13-55)packages/studiocms_socialposter/src/routes/postToThreads.ts (1)
POST(7-101)packages/studiocms_socialposter/src/utils/response.ts (1)
response(1-7)packages/studiocms_socialposter/astroenv.d.ts (3)
BLUESKY_PASSWORD(8-8)BLUESKY_SERVICE(6-6)BLUESKY_USERNAME(7-7)
🔇 Additional comments (2)
packages/studiocms_socialposter/src/routes/postToTwitter.ts (1)
13-55: Overall code structure and error handling look solid.
You have a clear sequence of checks, environment validation, and a tidy try-catch block. Great job organizing the route logic and returning consistent JSON responses!packages/studiocms_socialposter/src/routes/postToBlueSky.ts (1)
8-53: Execution flow and error handling are well-structured.
Appropriate checks for environment variables, user permission, and content are in place, and the try-catch approach ensures errors are captured. Nice work!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (3)
packages/studiocms_socialposter/src/routes/postToTwitter.ts (1)
40-54: Error handling is robust but could provide more specific errors.The error handling correctly catches exceptions, logs them, and returns appropriate error responses. Consider adding more specific error handling for common Twitter API errors such as rate limiting or duplicate tweets.
try { // Create the tweet await client.v2.tweet(content); return response(200, JSON.stringify({ message: 'Successfully sent Twitter/X message' })); } catch (e) { logger.error(`Error posting to Twitter / X: ${e}`); + // Check for specific Twitter API errors + const errorMessage = (e as Error).message || 'Failed to post to Twitter / X'; + const statusCode = 500; + + // Handle rate limiting errors + if (errorMessage.includes('rate limit')) { + return response(429, JSON.stringify({ + error: 'Twitter rate limit exceeded. Please try again later.', + })); + } + + // Handle duplicate tweet errors + if (errorMessage.includes('duplicate')) { + return response(400, JSON.stringify({ + error: 'Duplicate tweet. Please modify your message and try again.', + })); + } + return response( - 500, + statusCode, JSON.stringify({ - error: (e as Error).message || 'Failed to post to Twitter / X', + error: errorMessage, }) ); }packages/studiocms_socialposter/src/routes/postToBlueSky.ts (2)
31-41: Login and post operations may be inefficient.The current implementation logs in for each post request, which could be inefficient. Consider implementing a token caching mechanism to avoid logging in for each request.
try { - await agent.login({ - identifier: BLUESKY_USERNAME, - password: BLUESKY_PASSWORD, - }); + // Login and store session + let session; + try { + session = await agent.login({ + identifier: BLUESKY_USERNAME, + password: BLUESKY_PASSWORD, + }); + // In a production app, you might want to cache this session + } catch (loginError) { + logger.error(`Error logging into BlueSky: ${loginError}`); + return response( + 401, + JSON.stringify({ + error: 'Failed to authenticate with BlueSky', + }) + ); + } await agent.post({ text: content, createdAt: new Date().toISOString(), });
42-53: Error handling could be more specific.The error handling is good but could provide more specific error messages based on the type of error encountered.
return response(200, JSON.stringify({ message: 'Successfully sent BlueSky message' })); } catch (e) { logger.error(`Error posting to Bluesky: ${e}`); + const errorMessage = (e as Error).message || 'Failed to post to BlueSky'; + + // Handle specific BlueSky errors + if (errorMessage.includes('rate limit')) { + return response(429, JSON.stringify({ + error: 'BlueSky rate limit exceeded. Please try again later.', + })); + } + return response( 500, JSON.stringify({ - error: (e as Error).message || 'Failed to post to BlueSky', + error: errorMessage, }) ); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
packages/studiocms_socialposter/src/routes/postToBlueSky.ts(1 hunks)packages/studiocms_socialposter/src/routes/postToThreads.ts(1 hunks)packages/studiocms_socialposter/src/routes/postToTwitter.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/studiocms_socialposter/src/routes/postToThreads.ts
🧰 Additional context used
🧬 Code Definitions (2)
packages/studiocms_socialposter/src/routes/postToTwitter.ts (2)
packages/studiocms_socialposter/src/utils/response.ts (1)
response(1-7)packages/studiocms_socialposter/astroenv.d.ts (4)
TWITTER_API_KEY(2-2)TWITTER_API_SECRET(3-3)TWITTER_ACCESS_TOKEN(4-4)TWITTER_ACCESS_SECRET(5-5)
packages/studiocms_socialposter/src/routes/postToBlueSky.ts (2)
packages/studiocms_socialposter/src/utils/response.ts (1)
response(1-7)packages/studiocms_socialposter/astroenv.d.ts (3)
BLUESKY_PASSWORD(8-8)BLUESKY_SERVICE(6-6)BLUESKY_USERNAME(7-7)
🔇 Additional comments (8)
packages/studiocms_socialposter/src/routes/postToTwitter.ts (4)
1-12: Imports look well-organized and appropriate.The file correctly imports all necessary dependencies including Twitter API client, environment variables, and StudioCMS utilities for authentication and logging.
13-20: Good security implementation checking user permissions.The authentication flow correctly verifies that the user has editor permissions before allowing access to the Twitter posting functionality. The 403 response for unauthorized users follows best practices.
22-24: Environment variable validation is comprehensive.The code properly checks for all required Twitter API credentials before proceeding, preventing runtime errors from missing environment variables.
26-33: Twitter client initialization looks correct.The TwitterApi client is properly initialized with credentials from environment variables.
packages/studiocms_socialposter/src/routes/postToBlueSky.ts (4)
1-7: Imports are organized and appropriate.The file correctly imports all necessary dependencies for BlueSky API integration and StudioCMS utilities.
8-15: Authorization check is properly implemented.The code correctly verifies editor permissions before allowing access to the API functionality, following security best practices.
17-19: Environment variable validation is complete.All required BlueSky credentials are verified before proceeding with the operation.
27-30: BlueSky agent initialization looks correct.The AtpAgent is properly initialized with the service URL from environment variables.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (2)
packages/studiocms_socialposter/src/routes/postToTwitter.ts (1)
34-45: Content validation is comprehensiveThe code properly validates that content exists and doesn't exceed Twitter's 280 character limit.
packages/studiocms_socialposter/src/routes/postToBlueSky.ts (1)
21-29: Content validation is correctly implementedThe code properly validates that content exists and doesn't exceed BlueSky's 300 character limit, as suggested in the previous review.
🧹 Nitpick comments (2)
packages/studiocms_socialposter/src/routes/postToTwitter.ts (1)
47-61: Improve error handlingWhile the error handling looks generally good, consider checking if the error is an instance of Error before casting.
- error: (e as Error).message || 'Failed to post to Twitter / X', + error: e instanceof Error ? e.message : 'Failed to post to Twitter / X',packages/studiocms_socialposter/src/routes/postToBlueSky.ts (1)
47-56: Improve error handlingWhile the error handling looks generally good, consider checking if the error is an instance of Error before casting.
- error: (e as Error).message || 'Failed to post to BlueSky', + error: e instanceof Error ? e.message : 'Failed to post to BlueSky',
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
packages/studiocms_socialposter/src/routes/postToBlueSky.ts(1 hunks)packages/studiocms_socialposter/src/routes/postToThreads.ts(1 hunks)packages/studiocms_socialposter/src/routes/postToTwitter.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/studiocms_socialposter/src/routes/postToThreads.ts
🧰 Additional context used
🧬 Code Definitions (1)
packages/studiocms_socialposter/src/routes/postToTwitter.ts (2)
packages/studiocms_socialposter/src/utils/response.ts (1)
response(1-7)packages/studiocms_socialposter/astroenv.d.ts (4)
TWITTER_API_KEY(2-2)TWITTER_API_SECRET(3-3)TWITTER_ACCESS_TOKEN(4-4)TWITTER_ACCESS_SECRET(5-5)
🔇 Additional comments (8)
packages/studiocms_socialposter/src/routes/postToTwitter.ts (5)
1-12: LGTM: Clean imports and dependencies setupThe imports are well-organized, properly separated, and include all necessary dependencies for Twitter API integration.
13-21: Appropriate user permission validationGood implementation of permission checks to ensure only users with editor privileges can post to social media.
22-24: Environment variable validation looks goodProperly checking for all required Twitter API credentials before proceeding.
26-32: LGTM: Twitter client initializationThe Twitter client is correctly initialized with the necessary credentials from environment variables.
1-62:Details
✅ Verification successful
Consider adding support for media attachments
The current implementation only supports text content. In a future update, consider adding support for media attachments (images, videos) which are common in Twitter posts.
🌐 Web query:
Does Twitter API v2 support media attachments?💡 Result:
Yes, Twitter API v2 supports media attachments, but the implementation requires specific steps and authentication scopes. Here's a detailed breakdown:
Media Support in Twitter API v2
Direct media attachment is possible through the v2 API using the
media.media_idsparameter in tweet creation payloads[4][6]. However, media uploads currently rely on v1.1 media endpoints, creating a hybrid implementation requirement[5][6].Key implementation steps:
- Media upload via v1.1 endpoint:
media_id = api.upload_media(filename='image.jpg')- Tweet creation with v2 endpoint:
client.create_tweet(text='With media', media_ids=[media_id])Authentication Requirements
media.writescope needed for v2 media operations[1]- OAuth 1.0a still required for v1.1 media uploads[6]
Common Challenges
- Platform limitations: Some automation tools (like n8n) require manual scope additions to authorization URLs[1]
- Payload formatting: Media IDs must be nested under
media.media_idsin JSON payloads[3]- Multiple images: Supported through array of media IDs[5]
The official Twitter documentation confirms this hybrid approach, using v2 for tweet management while maintaining v1.1 media upload compatibility[6]. Developers should note that pure v2 media upload endpoints are still in development as of April 2025[1][3].
Citations:
- 1: https://community.n8n.io/t/post-media-to-x-twitter-via-api-new/90997
- 2: https://community.make.com/t/twitter-upload-api-v2/12067
- 3: https://community.n8n.io/t/adding-media-to-twitter-api-v2-with-http-node/27396
- 4: https://docs.tweepy.org/en/stable/v2_models.html
- 5: https://github.com/plhery/node-twitter-api-v2/blob/master/doc/v2.md
- 6: https://developer.x.com/en/docs/tutorials/tweeting-media-v2
Enhancement for Media Attachments Support in Twitter Posting
The current implementation is correctly handling text-only tweets, and as a future enhancement, consider extending it to allow media attachments. Twitter API v2 does support media attachments; however, it requires a hybrid approach—using Twitter’s v1.1 media endpoint for uploads and then referencing the returned media IDs when creating a tweet via the v2 endpoint. When planning this enhancement, keep in mind:
- Media Upload: Use the v1.1 endpoint to upload media files (image/video) to obtain media IDs.
- Tweet Creation: Modify the tweet creation call to include a
media.media_idsarray along with the text content.- Authentication Scopes: Ensure that the OAuth tokens include the appropriate scopes (e.g.,
media.write) required for media uploads.- Payload Validation: Validate media file types and limits according to Twitter's API documentation before attempting an upload.
These adjustments could improve the feature set without disrupting the current text-only functionality.
packages/studiocms_socialposter/src/routes/postToBlueSky.ts (3)
1-7: LGTM: Clean imports and dependencies setupThe imports are well-organized and include all necessary dependencies for BlueSky API integration.
8-15: Appropriate user permission validationGood implementation of permission checks to ensure only users with editor privileges can post to social media.
17-19: Environment variable validation looks goodProperly checking for all required BlueSky API credentials before proceeding.
Initial release of the plugin, more features and functionality coming in the future.
Summary by CodeRabbit
New Features
Documentation
LICENSEfile outlining the MIT License for the new package.socialPosterplugin.