Skip to content

Conversation

@Adammatthiesen
Copy link
Member

@Adammatthiesen Adammatthiesen commented Apr 7, 2025

Initial release of the plugin, more features and functionality coming in the future.

image

Summary by CodeRabbit

  • New Features

    • Introduced a social media cross-posting module for StudioCMS that lets you publish directly to Twitter, BlueSky, and Threads.
    • Added a streamlined, rich text editor interface with toggle switches and live character counters for easy post composition.
    • Enabled new plugin options for configuring social media integrations within StudioCMS.
  • Documentation

    • Provided comprehensive setup and usage guidelines to help you integrate and customize the new social posting features.
    • Added a LICENSE file outlining the MIT License for the new package.
    • Created a README file detailing the functionality and requirements for the social posting module.
    • Updated configuration documentation to reflect the inclusion of the new socialPoster plugin.
    • Introduced a new TypeScript declaration file for enhanced type safety and usability.

@changeset-bot
Copy link

changeset-bot bot commented Apr 7, 2025

🦋 Changeset detected

Latest commit: d3aa44f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@studiocms/socialposter Patch

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Apr 7, 2025

Walkthrough

This pull request adds a new package, @studiocms/socialposter, which integrates social media posting functionality into StudioCMS. New files include package metadata, TypeScript definitions, utility functions, API endpoints for BlueSky, Threads, and Twitter, and a UI page for composing posts. Additionally, configuration files such as .vscode/settings.json and pnpm-workspace.yaml are updated, and the StudioCMS configuration is extended to include the new social posting plugin.

Changes

File Change Summary
.changeset/every-seas-judge.md Created file declaring initial release patch for @studiocms/socialposter.
.vscode/settings.json Added new words ("astroenv", "atproto", "bsky", "socialposter", "virtuals") to the cSpell.words array.
packages/studiocms_socialposter/... Added new package files including:
- .gitignore: Ignore patterns for generated files and dependencies.
- LICENSE: MIT License.
- README.md: Plugin docs.
- package.json: Metadata and config.
- tsconfig.json: TS configuration.
packages/studiocms_socialposter/src/... Introduced plugin implementation and related files:
- index.ts: Plugin function and option interface.
- pages/socials.astro: UI for composing posts.
- routes/postToBlueSky.ts, postToThreads.ts, postToTwitter.ts: API endpoints for social media posting.
- utils/astroEnvConfig.ts & response.ts: Utility functions.
- virtuals.d.ts: Module declaration for configuration.
packages/studiocms_socialposter/ui.d.ts Added UI component declarations and helper classes for StudioCMS integration.
playground/package.json and playground/studiocms.config.mjs Added dependency on @studiocms/socialposter and updated StudioCMS configuration to include the new socialPoster plugin with specified options.
pnpm-workspace.yaml Updated dependency versions for @studiocms/blog, @studiocms/devapps, and studiocms from beta 13 to beta 14.

Suggested Reviewers

  • RATIU5
  • dreyfus92
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Apr 7, 2025

Open in StackBlitz

npm i https://pkg.pr.new/withstudiocms/experiments/@studiocms/grapesjs-plugin@6
npm i https://pkg.pr.new/withstudiocms/experiments/@studiocms/socialposter@6
npm i https://pkg.pr.new/withstudiocms/experiments/@studiocms/wysiwyg@6

commit: d3aa44f

@Adammatthiesen Adammatthiesen changed the title Add new Social poster plugin Add new social media poster plugin Apr 7, 2025
@Adammatthiesen Adammatthiesen marked this pull request as ready for review April 7, 2025 16:07
@Adammatthiesen Adammatthiesen requested a review from a team as a code owner April 7, 2025 16:07
Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 Valladares
packages/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 configuration

The addAstroEnvConfig utility function is well-defined using the astro-integration-kit's defineUtility and 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 documentation

The 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.log for debugging purposes. For consistency with other routes, consider using the logger module 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": false is 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 setting sideEffects to 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, and updateTwitter methods 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

📥 Commits

Reviewing files that changed from the base of the PR and between 02b9930 and ef536d5.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is 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/socialposter package.

playground/package.json (1)

28-28: Dependency addition looks good.

Correctly added the @studiocms/socialposter package 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 correctly

The 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 enabled

The 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 safety

The imports are correctly defined with proper type safety for Astro configuration objects.

packages/studiocms_socialposter/README.md (3)

1-4: Clear and concise plugin introduction

The README starts with a clear title and description, effectively communicating the plugin's purpose.


26-44: Clear usage instructions with example

The 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 false by default) and the actual implementation in studiocms.config.mjs (which sets all platforms to true). Verify which is the intended default configuration.


46-48: License information included

The license information is correctly included, referencing the LICENSE file.

pnpm-workspace.yaml (1)

5-6: Version updates for consistency

The 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/socialposter is 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 multiple package.json files, pnpm-workspace.yaml, and pnpm-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 defaultOptions is 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.

Adammatthiesen and others added 2 commits April 7, 2025 09:12
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
coderabbitai[bot]
coderabbitai bot previously approved these changes Apr 7, 2025
coderabbitai[bot]
coderabbitai bot previously approved these changes Apr 7, 2025
dreyfus92
dreyfus92 previously approved these changes Apr 7, 2025
Copy link
Member

@dreyfus92 dreyfus92 left a 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 😭

@Adammatthiesen
Copy link
Member Author

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 🤣

RATIU5
RATIU5 previously approved these changes Apr 7, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

📥 Commits

Reviewing files that changed from the base of the PR and between c89ae02 and 96e27bb.

📒 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!

coderabbitai[bot]
coderabbitai bot previously approved these changes Apr 8, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

📥 Commits

Reviewing files that changed from the base of the PR and between 96e27bb and 9b9d0fb.

📒 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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 comprehensive

The 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 implemented

The 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 handling

While 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 handling

While 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

📥 Commits

Reviewing files that changed from the base of the PR and between 9b9d0fb and d3aa44f.

📒 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 setup

The imports are well-organized, properly separated, and include all necessary dependencies for Twitter API integration.


13-21: Appropriate user permission validation

Good implementation of permission checks to ensure only users with editor privileges can post to social media.


22-24: Environment variable validation looks good

Properly checking for all required Twitter API credentials before proceeding.


26-32: LGTM: Twitter client initialization

The 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_ids parameter 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:

  1. Media upload via v1.1 endpoint:
    media_id = api.upload_media(filename='image.jpg')
  2. Tweet creation with v2 endpoint:
    client.create_tweet(text='With media', media_ids=[media_id])

Authentication Requirements

  • media.write scope 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_ids in 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:


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_ids array 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 setup

The imports are well-organized and include all necessary dependencies for BlueSky API integration.


8-15: Appropriate user permission validation

Good implementation of permission checks to ensure only users with editor privileges can post to social media.


17-19: Environment variable validation looks good

Properly checking for all required BlueSky API credentials before proceeding.

@Adammatthiesen Adammatthiesen merged commit f2f6430 into main Apr 8, 2025
11 checks passed
@Adammatthiesen Adammatthiesen deleted the social-poster branch April 8, 2025 02:35
@coderabbitai coderabbitai bot mentioned this pull request Apr 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants