diff --git a/.changeset/every-seas-judge.md b/.changeset/every-seas-judge.md new file mode 100644 index 0000000..b87b080 --- /dev/null +++ b/.changeset/every-seas-judge.md @@ -0,0 +1,5 @@ +--- +"@studiocms/socialposter": patch +--- + +Initial release diff --git a/.vscode/settings.json b/.vscode/settings.json index 1809477..f698a1c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,8 +4,11 @@ "alignjustify", "alignleft", "alignright", + "astroenv", + "atproto", "Avenir", "backcolor", + "bsky", "bullist", "cmdm", "CMSWYSIWYG", @@ -19,10 +22,12 @@ "numlist", "outdent", "projectdata", + "socialposter", "strikethrough", "studiocms", "studiosdk", "toastr", + "virtuals", "withstudiocms", "WYSIWYGDB" ] diff --git a/packages/studiocms_socialposter/.gitignore b/packages/studiocms_socialposter/.gitignore new file mode 100644 index 0000000..8f18003 --- /dev/null +++ b/packages/studiocms_socialposter/.gitignore @@ -0,0 +1,23 @@ + +# 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/ \ No newline at end of file diff --git a/packages/studiocms_socialposter/LICENSE b/packages/studiocms_socialposter/LICENSE new file mode 100644 index 0000000..443a97b --- /dev/null +++ b/packages/studiocms_socialposter/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 StudioCMS - Adam Matthiesen, Jacob Jenkins, Paul Valladares + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/packages/studiocms_socialposter/README.md b/packages/studiocms_socialposter/README.md new file mode 100644 index 0000000..51bf069 --- /dev/null +++ b/packages/studiocms_socialposter/README.md @@ -0,0 +1,48 @@ +# @StudioCMS/socialposter Plugin + +Allow cross-posting to your social media accounts from your StudioCMS dashboard with ease! + +## Requirements + +Depending on which services you are trying to post on you may require one of more of the following variables in your `.env` + +```bash +# Twitter/X +TWITTER_API_KEY=your_api_key +TWITTER_API_SECRET=your_api_secret +TWITTER_ACCESS_TOKEN=your_access_token +TWITTER_ACCESS_SECRET=your_access_secret + +# Bluesky +BLUESKY_SERVICE=https://bsky.social +BLUESKY_USERNAME=your_username +BLUESKY_PASSWORD=your_password + +# Threads/Instagram +THREADS_USER_ID=your_user_id +THREADS_ACCESS_TOKEN=your_access_token +``` + +### Usage + +Add this plugin in your StudioCMS config (`studiocms.config.mjs`) and enable the desired options. + +```ts +import { defineStudioCMSConfig } from 'studiocms/config'; +import socialPoster from '@studiocms/socialposter'; + +export default defineStudioCMSConfig({ + // other options here + plugins: [ + socialPoster({ + bluesky: false, + threads: false, + twitter: false, + }) + ], +}); +``` + +## License + +[MIT Licensed](./LICENSE). \ No newline at end of file diff --git a/packages/studiocms_socialposter/astroenv.d.ts b/packages/studiocms_socialposter/astroenv.d.ts new file mode 100644 index 0000000..80e50f8 --- /dev/null +++ b/packages/studiocms_socialposter/astroenv.d.ts @@ -0,0 +1,11 @@ +declare module 'astro:env/server' { + export const TWITTER_API_KEY: string | undefined; + export const TWITTER_API_SECRET: string | undefined; + export const TWITTER_ACCESS_TOKEN: string | undefined; + export const TWITTER_ACCESS_SECRET: string | undefined; + export const BLUESKY_SERVICE: string | undefined; + export const BLUESKY_USERNAME: string | undefined; + export const BLUESKY_PASSWORD: string | undefined; + export const THREADS_USER_ID: string | undefined; + export const THREADS_ACCESS_TOKEN: string | undefined; +} diff --git a/packages/studiocms_socialposter/package.json b/packages/studiocms_socialposter/package.json new file mode 100644 index 0000000..1d8a706 --- /dev/null +++ b/packages/studiocms_socialposter/package.json @@ -0,0 +1,63 @@ +{ + "name": "@studiocms/socialposter", + "version": "0.1.0-experimental.0", + "description": "Allow cross-posting to your social media accounts from your StudioCMS dashboard with ease!", + "author": { + "name": "Adam Matthiesen | Jacob Jenkins | Paul Valladares", + "url": "https://studiocms.dev" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/withstudiocms/experiments.git", + "directory": "packages/studiocms_socialposter" + }, + "contributors": ["Adammatthiesen", "jdtjenkins", "dreyfus92", "code.spirit"], + "license": "MIT", + "keywords": [ + "astro", + "astrocms", + "astrodb", + "astrostudio", + "astro-integration", + "astro-studio", + "astro-studiocms", + "cms", + "studiocms", + "withastro", + "plugin", + "studiocms-plugin" + ], + "homepage": "https://studiocms.dev", + "publishConfig": { + "access": "public", + "provenance": true + }, + "sideEffects": false, + "files": ["dist"], + "scripts": { + "build": "build-scripts build 'src/**/*.{ts,astro,css,js}'", + "dev": "build-scripts dev 'src/**/*.{ts,astro,css,js}'" + }, + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + }, + "type": "module", + "dependencies": { + "@atproto/api": "^0.14.20", + "@studiocms/ui": "^0.4.16", + "astro-integration-kit": "catalog:", + "twitter-api-v2": "^1.22.0", + "quill": "^2.0.3" + }, + "devDependencies": { + "@types/node": "catalog:" + }, + "peerDependencies": { + "astro": "catalog:min", + "studiocms": "catalog:min", + "vite": "catalog:min" + } +} diff --git a/packages/studiocms_socialposter/src/index.ts b/packages/studiocms_socialposter/src/index.ts new file mode 100644 index 0000000..eb58e83 --- /dev/null +++ b/packages/studiocms_socialposter/src/index.ts @@ -0,0 +1,151 @@ +/** + * These triple-slash directives defines dependencies to various declaration files that will be + * loaded when a user imports the StudioCMS plugin in their Astro configuration file. These + * directives must be first at the top of the file and can only be preceded by this comment. + */ +/// +/// +/// +/// +import { addVirtualImports, createResolver } from 'astro-integration-kit'; +import { type StudioCMSPlugin, definePlugin } from 'studiocms/plugins'; +import { addAstroEnvConfig } from './utils/astroEnvConfig.js'; +import { envField } from 'astro/config'; + +export interface StudioCMSSocialPosterOptions { + bluesky: boolean; + threads: boolean; + twitter: boolean; +} + +const defaultOptions: StudioCMSSocialPosterOptions = { + bluesky: false, + threads: false, + twitter: false, +}; + +function studiocmsSocialPoster(opts?: Partial): StudioCMSPlugin { + // Resolve the path to the current file + const { resolve } = createResolver(import.meta.url); + + // Define the package identifier + const packageIdentifier = '@studiocms/socialposter'; + + const options: StudioCMSSocialPosterOptions = { + ...defaultOptions, + ...opts, + }; + + return definePlugin({ + identifier: packageIdentifier, + name: 'StudioCMS Social Poster', + studiocmsMinimumVersion: '0.1.0-beta.14', + dashboardPages: { + user: [ + { + title: { + 'en-us': 'Share to Social Media', + }, + description: 'Share content on Social media', + sidebar: 'single', + pageBodyComponent: resolve('./pages/socials.astro'), + route: 'share', + requiredPermissions: 'editor', + icon: 'share', + }, + ], + }, + integration: { + name: packageIdentifier, + hooks: { + 'astro:config:setup': (params) => { + const { injectRoute } = params; + + addAstroEnvConfig(params, { + validateSecrets: true, + schema: { + BLUESKY_SERVICE: envField.string({ + context: 'server', + access: 'secret', + optional: !options.bluesky, + }), + BLUESKY_USERNAME: envField.string({ + context: 'server', + access: 'secret', + optional: !options.bluesky, + }), + BLUESKY_PASSWORD: envField.string({ + context: 'server', + access: 'secret', + optional: !options.bluesky, + }), + THREADS_USER_ID: envField.string({ + context: 'server', + access: 'secret', + optional: !options.threads, + }), + THREADS_ACCESS_TOKEN: envField.string({ + context: 'server', + access: 'secret', + optional: !options.threads, + }), + TWITTER_API_KEY: envField.string({ + context: 'server', + access: 'secret', + optional: !options.twitter, + }), + TWITTER_API_SECRET: envField.string({ + context: 'server', + access: 'secret', + optional: !options.twitter, + }), + TWITTER_ACCESS_TOKEN: envField.string({ + context: 'server', + access: 'secret', + optional: !options.twitter, + }), + TWITTER_ACCESS_SECRET: envField.string({ + context: 'server', + access: 'secret', + optional: !options.twitter, + }), + }, + }); + + addVirtualImports(params, { + name: packageIdentifier, + imports: { + 'studiocms:socialposter/config': `export default ${JSON.stringify(options)}`, + }, + }); + + if (options.bluesky) { + injectRoute({ + pattern: '/studiocms_api/socialposter/post-to-bluesky', + entrypoint: resolve('./routes/postToBlueSky.js'), + prerender: false, + }); + } + + if (options.threads) { + injectRoute({ + pattern: '/studiocms_api/socialposter/post-to-threads', + entrypoint: resolve('./routes/postToThreads.js'), + prerender: false, + }); + } + + if (options.twitter) { + injectRoute({ + pattern: '/studiocms_api/socialposter/post-to-twitter', + entrypoint: resolve('./routes/postToTwitter.js'), + prerender: false, + }); + } + }, + }, + }, + }); +} + +export default studiocmsSocialPoster; diff --git a/packages/studiocms_socialposter/src/pages/socials.astro b/packages/studiocms_socialposter/src/pages/socials.astro new file mode 100644 index 0000000..fba9043 --- /dev/null +++ b/packages/studiocms_socialposter/src/pages/socials.astro @@ -0,0 +1,413 @@ +--- +import 'quill/dist/quill.snow.css'; +import socialsConfig from 'studiocms:socialposter/config'; +import { Card, Toggle, Button, Icon } from 'studiocms:ui/components'; + +const { bluesky, threads, twitter } = socialsConfig; + +const options = [ + { + label: 'BlueSky', + name: 'bluesky', + counterId: 'bsky-counter', + limit: 300, + enabled: bluesky, + }, + { + label: 'Threads / Instagram', + name: 'threads', + counterId: 'threads-counter', + limit: 500, + enabled: threads, + }, + { + label: 'Twitter / X', + name: 'twitter', + counterId: 'twitter-counter', + limit: 280, + enabled: twitter, + }, +]; +--- +
+ + {/* + + // TODO: Add support for being able to display pages and their current content to make it easy to get excerpts for creating new posts. + + */} + + +
+

Create Your Post

+
+ +
+ +
+ + { + options + .filter(({enabled}) => enabled === true) + .map(({ label, limit, name, counterId }) => ( +
+ +
0 / {limit}
+
+ )) + } + +
+ +
+ + +
+
+
+ + + + + + \ No newline at end of file diff --git a/packages/studiocms_socialposter/src/routes/postToBlueSky.ts b/packages/studiocms_socialposter/src/routes/postToBlueSky.ts new file mode 100644 index 0000000..696cc7e --- /dev/null +++ b/packages/studiocms_socialposter/src/routes/postToBlueSky.ts @@ -0,0 +1,57 @@ +import type { APIContext, APIRoute } from 'astro'; +import { AtpAgent } from '@atproto/api'; +import { BLUESKY_PASSWORD, BLUESKY_SERVICE, BLUESKY_USERNAME } from 'astro:env/server'; +import logger from 'studiocms:logger'; +import { response } from '../utils/response.js'; +import { getUserData, verifyUserPermissionLevel } from 'studiocms:auth/lib/user'; + +export const POST: APIRoute = async (context: APIContext) => { + const userSessionData = await getUserData(context); + + const isEditor = await verifyUserPermissionLevel(userSessionData, 'editor'); + + if (!isEditor) { + return response(403, JSON.stringify({ error: 'Forbidden' })); + } + + if (!BLUESKY_PASSWORD || !BLUESKY_SERVICE || !BLUESKY_USERNAME) { + return response(500, JSON.stringify({ error: 'Missing ENV Variables' })); + } + + const { content } = await context.request.json(); + + if (!content) { + return response(400, JSON.stringify({ error: 'Content must not be empty' })); + } + + if (content.length > 300) { + return response(400, JSON.stringify({ error: 'Content exceeds the 300-character limit' })); + } + + const agent = new AtpAgent({ + service: new URL(BLUESKY_SERVICE), + }); + + try { + await agent.login({ + identifier: BLUESKY_USERNAME, + password: BLUESKY_PASSWORD, + }); + + await agent.post({ + text: content, + createdAt: new Date().toISOString(), + }); + + return response(200, JSON.stringify({ message: 'Successfully sent BlueSky message' })); + } catch (e) { + logger.error(`Error posting to Bluesky: ${e}`); + + return response( + 500, + JSON.stringify({ + error: (e as Error).message || 'Failed to post to BlueSky', + }) + ); + } +}; diff --git a/packages/studiocms_socialposter/src/routes/postToThreads.ts b/packages/studiocms_socialposter/src/routes/postToThreads.ts new file mode 100644 index 0000000..f751af3 --- /dev/null +++ b/packages/studiocms_socialposter/src/routes/postToThreads.ts @@ -0,0 +1,105 @@ +import { THREADS_ACCESS_TOKEN, THREADS_USER_ID } from 'astro:env/server'; +import { response } from '../utils/response.js'; +import type { APIContext, APIRoute } from 'astro'; +import logger from 'studiocms:logger'; +import { getUserData, verifyUserPermissionLevel } from 'studiocms:auth/lib/user'; + +export const POST: APIRoute = async (context: APIContext) => { + const userSessionData = await getUserData(context); + + const isEditor = await verifyUserPermissionLevel(userSessionData, 'editor'); + + if (!isEditor) { + return response(403, JSON.stringify({ error: 'Forbidden' })); + } + + if (!THREADS_ACCESS_TOKEN || !THREADS_USER_ID) { + return response(500, JSON.stringify({ error: 'Missing ENV Variables' })); + } + + const { content } = await context.request.json(); + + if (!content) { + return response(400, JSON.stringify({ error: 'Content must not be empty' })); + } + + if (content.length > 500) { + return response(400, JSON.stringify({ error: 'Content exceeds the 300-character limit' })); + } + + try { + console.log('Creating Threads post container...'); + + const createResponseParams = new URLSearchParams({ + text: content, + access_token: THREADS_ACCESS_TOKEN, + media_type: 'TEXT', + }); + + const createResponse = await fetch( + `https://graph.threads.net/v1.0/${THREADS_USER_ID}/threads?${createResponseParams.toString()}`, + { + method: 'POST', + } + ); + + const createResponseData = await createResponse.json(); + + console.log('Create response:', createResponseData); + + if (!createResponseData.id) { + throw new Error('Failed to get post container ID'); + } + + console.log('Publishing Threads post...'); + + const params = new URLSearchParams({ + creation_id: createResponseData.id, + access_token: THREADS_ACCESS_TOKEN, + }); + + const publishResponse = await fetch( + `https://graph.threads.net/v1.0/${THREADS_USER_ID}/threads_publish?${params.toString()}`, + { + method: 'POST', + } + ); + + const publishResponseData = await publishResponse.json(); + + console.log('Publish response:', publishResponseData); + + return response(200, JSON.stringify('Successfully sent Threads message')); + } catch (e) { + logger.error(`Threads API Error: ${e}`); + + // Type the error appropriately + type ApiError = Error & { + response?: { + data?: { + error?: { message?: string }; + message?: string; + }; + status?: number; + }; + config?: { + url?: string; + params?: Record; + }; + }; + + const err = e as ApiError; + const errorMessage = + err.response?.data?.error?.message || + err.response?.data?.message || + err.message || + 'Failed to post to Threads'; + + return response( + 500, + JSON.stringify({ + error: errorMessage, + }) + ); + } +}; diff --git a/packages/studiocms_socialposter/src/routes/postToTwitter.ts b/packages/studiocms_socialposter/src/routes/postToTwitter.ts new file mode 100644 index 0000000..f8ef02b --- /dev/null +++ b/packages/studiocms_socialposter/src/routes/postToTwitter.ts @@ -0,0 +1,62 @@ +import { + TWITTER_ACCESS_SECRET, + TWITTER_ACCESS_TOKEN, + TWITTER_API_KEY, + TWITTER_API_SECRET, +} from 'astro:env/server'; +import logger from 'studiocms:logger'; +import { response } from '../utils/response.js'; +import type { APIContext, APIRoute } from 'astro'; +import { TwitterApi } from 'twitter-api-v2'; +import { getUserData, verifyUserPermissionLevel } from 'studiocms:auth/lib/user'; + +export const POST: APIRoute = async (context: APIContext) => { + const userSessionData = await getUserData(context); + + const isEditor = await verifyUserPermissionLevel(userSessionData, 'editor'); + + if (!isEditor) { + return response(403, JSON.stringify({ error: 'Forbidden' })); + } + + if (!TWITTER_API_KEY || !TWITTER_API_SECRET || !TWITTER_ACCESS_TOKEN || !TWITTER_ACCESS_SECRET) { + return response(500, JSON.stringify({ error: 'Missing ENV Variables' })); + } + + // Initialize the Twitter client with credentials from environment variables + const client = new TwitterApi({ + appKey: TWITTER_API_KEY, + appSecret: TWITTER_API_SECRET, + accessToken: TWITTER_ACCESS_TOKEN, + accessSecret: TWITTER_ACCESS_SECRET, + }); + + const { content } = await context.request.json(); + + if (!content) { + return response(400, JSON.stringify({ error: 'Content must not be empty' })); + } + + if (content.length > 280) { + return response( + 400, + JSON.stringify({ error: "Content exceeds Twitter's 280 character limit" }) + ); + } + + 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}`); + + return response( + 500, + JSON.stringify({ + error: (e as Error).message || 'Failed to post to Twitter / X', + }) + ); + } +}; diff --git a/packages/studiocms_socialposter/src/utils/astroEnvConfig.ts b/packages/studiocms_socialposter/src/utils/astroEnvConfig.ts new file mode 100644 index 0000000..1445c94 --- /dev/null +++ b/packages/studiocms_socialposter/src/utils/astroEnvConfig.ts @@ -0,0 +1,12 @@ +import type { AstroConfig } from 'astro'; +import { defineUtility } from 'astro-integration-kit'; + +/** + * Add Astro Environment Variables Config for using 'astro:env' + */ +export const addAstroEnvConfig = defineUtility('astro:config:setup')( + (params, env: AstroConfig['env']) => { + // Update Astro Config with Environment Variables (`astro:env`) + params.updateConfig({ env }); + } +); diff --git a/packages/studiocms_socialposter/src/utils/response.ts b/packages/studiocms_socialposter/src/utils/response.ts new file mode 100644 index 0000000..43d1dd7 --- /dev/null +++ b/packages/studiocms_socialposter/src/utils/response.ts @@ -0,0 +1,7 @@ +export const response = (status: number, data: string) => + new Response(data, { + status, + headers: { + 'Content-Type': 'application/json', + }, + }); diff --git a/packages/studiocms_socialposter/src/virtuals.d.ts b/packages/studiocms_socialposter/src/virtuals.d.ts new file mode 100644 index 0000000..2b3bb8d --- /dev/null +++ b/packages/studiocms_socialposter/src/virtuals.d.ts @@ -0,0 +1,4 @@ +declare module 'studiocms:socialposter/config' { + const options: import('./index').StudioCMSSocialPosterOptions; + export default options; +} diff --git a/packages/studiocms_socialposter/tsconfig.json b/packages/studiocms_socialposter/tsconfig.json new file mode 100644 index 0000000..fbad20b --- /dev/null +++ b/packages/studiocms_socialposter/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src"], + "compilerOptions": { + "outDir": "./dist", + "emitDeclarationOnly": true, + "rootDir": "./src" + } +} diff --git a/packages/studiocms_socialposter/ui.d.ts b/packages/studiocms_socialposter/ui.d.ts new file mode 100644 index 0000000..837d851 --- /dev/null +++ b/packages/studiocms_socialposter/ui.d.ts @@ -0,0 +1,291 @@ +declare module 'studiocms:ui/version' { + const version: string; + export default version; +} + +declare module 'studiocms:ui/global-css' {} + +declare module 'studiocms:ui/custom-css' {} + +declare module 'studiocms:ui/scripts/*' {} + +declare module 'studiocms:ui/components' { + export const Button: typeof import('@studiocms/ui/components/Button/Button.astro').default; + export const Divider: typeof import('@studiocms/ui/components/Divider/Divider.astro').default; + export const Input: typeof import('@studiocms/ui/components/Input/Input.astro').default; + export const Row: typeof import('@studiocms/ui/components/Row/Row.astro').default; + export const Center: typeof import('@studiocms/ui/components/Center/Center.astro').default; + export const Textarea: typeof import('@studiocms/ui/components/Textarea/Textarea.astro').default; + export const Checkbox: typeof import('@studiocms/ui/components/Checkbox/Checkbox.astro').default; + export const Toggle: typeof import('@studiocms/ui/components/Toggle/Toggle.astro').default; + export const RadioGroup: typeof import( + '@studiocms/ui/components/RadioGroup/RadioGroup.astro' + ).default; + export const Toaster: typeof import('@studiocms/ui/components/Toast/Toaster.astro').default; + export const Card: typeof import('@studiocms/ui/components/Card/Card.astro').default; + export const Modal: typeof import('@studiocms/ui/components/Modal/Modal.astro').default; + export const Select: typeof import('@studiocms/ui/components/Select/Select.astro').default; + export const SearchSelect: typeof import( + '@studiocms/ui/components/SearchSelect/SearchSelect.astro' + ).default; + export const Dropdown: typeof import('@studiocms/ui/components/Dropdown/Dropdown.astro').default; + export const User: typeof import('@studiocms/ui/components/User/User.astro').default; + export const ThemeToggle: typeof import( + '@studiocms/ui/components/ThemeToggle/ThemeToggle.astro' + ).default; + export const Tabs: typeof import('@studiocms/ui/components/Tabs/Tabs.astro').default; + export const TabItem: typeof import('@studiocms/ui/components/Tabs/TabItem.astro').default; + export const Accordion: typeof import( + '@studiocms/ui/components/Accordion/Accordion.astro' + ).default; + export const AccordionItem: typeof import( + '@studiocms/ui/components/Accordion/Item.astro' + ).default; + export const Footer: typeof import('@studiocms/ui/components/Footer/Footer.astro').default; + export const Progress: typeof import('@studiocms/ui/components/Progress/Progress.astro').default; + export const Sidebar: typeof import('@studiocms/ui/components/Sidebar/Single.astro').default; + export const DoubleSidebar: typeof import( + '@studiocms/ui/components/Sidebar/Double.astro' + ).default; + export const Breadcrumbs: typeof import( + '@studiocms/ui/components/Breadcrumbs/Breadcrumbs.astro' + ).default; + export const Group: typeof import('@studiocms/ui/components/Group/Group.astro').default; + export const Badge: typeof import('@studiocms/ui/components/Badge/Badge.astro').default; + export const Icon: typeof import('@studiocms/ui/components/Icon/Icon.astro').default; + export const IconBase: typeof import('@studiocms/ui/components/Icon/IconBase.astro').default; + export const toast: typeof import('@studiocms/ui/components/Toast/toast.js').toast; + export type HeroIconName = import('@studiocms/ui/components/Icon/iconType.js').HeroIconName; + + export class ModalHelper { + private element; + private cancelButton; + private confirmButton; + private isForm; + private modalForm; + /** + * A helper to manage modals. + * @param id The ID of the modal. + * @param triggerID The ID of the element that should trigger the modal. + */ + constructor(id: string, triggerID?: string); + /** + * A helper function which adds event listeners to the modal buttons to close the modal when clicked. + * @param id The ID of the modal. + * @param dismissable Whether the modal is dismissable. + */ + private addButtonListeners; + /** + * A helper function to close the modal when the user clicks outside of it. + */ + private addDismissiveClickListener; + /** + * A function to show the modal. + */ + show: () => void; + /** + * A function to hide the modal. + */ + hide: () => void; + /** + * A function to add another trigger to show the modal with. + * @param elementID The ID of the element that should trigger the modal when clicked. + */ + bindTrigger: (elementID: string) => void; + /** + * Registers a callback for the cancel button. + * @param func The callback function. + */ + registerCancelCallback: (func: () => void) => void; + /** + * Registers a callback for the confirm button. + * @param func The callback function. If the modal is a form, the function will be called with + * the form data as the first argument. + */ + registerConfirmCallback: (func: (data?: FormData | undefined) => void) => void; + } + + export class DropdownHelper { + private container; + private toggleEl; + private dropdown; + private alignment; + private triggerOn; + private fullWidth; + private focusIndex; + active: boolean; + /** + * A helper function to interact with dropdowns. + * @param id The ID of the dropdown. + * @param fullWidth Whether the dropdown should be full width. Not needed normally. + */ + constructor(id: string, fullWidth?: boolean); + /** + * Registers a click callback for the dropdown options. Whenever one of the options + * is clicked, the callback will be called with the value of the option. + * @param func The callback function. + */ + registerClickCallback: (func: (value: string) => void) => void; + /** + * Sets up all listeners for the dropdown. + */ + private initialBehaviorRegistration; + /** + * Registers callbacks to hide the dropdown when an option is clicked. + */ + private initialOptClickRegistration; + /** + * A function to toggle the dropdown. + */ + toggle: () => void; + /** + * A function to hide the dropdown. + */ + hide: () => void; + /** + * A function to show the dropdown. + */ + show: () => void; + /** + * A jQuery-like function to hide the dropdown when clicking outside of it. + * @param element The element to hide when clicking outside of it. + */ + private hideOnClickOutside; + } + + export class ProgressHelper { + private bar; + private progress; + private value; + private max; + constructor(id: string); + getValue(): number; + setValue(value: number): void; + getMax(): number; + setMax(value: number): void; + getPercentage(): number; + } + + export class SingleSidebarHelper { + private sidebar; + private sidebarToggle?; + /** + * A helper to manage the sidebar with. + * @param toggleID The ID of the element that should toggle the sidebar. + */ + constructor(toggleID?: string); + /** + * A helper function register an element which should toggle the sidebar. + * @param elementID The ID of the element that should toggle the sidebar. + */ + toggleSidebarOnClick: (elementID: string) => void; + /** + * A helper function to hide the sidebar when an element is clicked. + * @param elementID The ID of the element that should hide the sidebar. + */ + hideSidebarOnClick: (elementID: string) => void; + /** + * A helper function to show the sidebar when an element is clicked. + * @param elementID The ID of the element that should show the sidebar. + */ + showSidebarOnClick: (elementID: string) => void; + /** + * A function to hide the sidebar. + */ + hideSidebar: () => void; + /** + * A function to show the sidebar. + */ + showSidebar: () => void; + } + + export class DoubleSidebarHelper { + private sidebarsContainer; + /** + * A helper to manage the double sidebar with. + */ + constructor(); + /** + * A helper function to hide the sidebar when an element is clicked. + * @param elementID The ID of the element that should hide the sidebar. + */ + hideSidebarOnClick: (elementID: string) => void; + /** + * A helper function to show the outer sidebar when an element is clicked. + * @param elementID The ID of the element that should show the outer sidebar. + */ + showOuterOnClick: (elementID: string) => void; + /** + * A helper function to show the inner sidebar when an element is clicked. + * @param elementID The ID of the element that should show the inner sidebar. + */ + showInnerOnClick: (elementID: string) => void; + /** + * A function to show the inner sidebar. + */ + showInnerSidebar: () => void; + /** + * A function to show the outer sidebar. + */ + showOuterSidebar: () => void; + /** + * A function to hide the sidebar altogether. + */ + hideSidebar: () => void; + } +} + +declare module 'studiocms:ui/utils' { + export type Theme = import('@studiocms/ui/utils/ThemeHelper.js').Theme; + + type ThemeChangeCallback = (newTheme: Theme, oldTheme: Theme) => void; + + /** + * A helper to toggle, set and get the current StudioCMS UI theme. + */ + export class ThemeHelper { + private themeManagerElement; + private observer; + private themeChangeCallbacks; + /** + * A helper to toggle, set and get the current StudioCMS UI theme. + * @param themeProvider The element that should carry the data-theme attribute (replaces the document root) + */ + constructor(themeProvider?: HTMLElement); + /** + * Get the current theme. + * @param {boolean} resolveSystemTheme Whether to resolve the `system` theme to the actual theme (`dark` or `light`) + * @returns {Theme} The current theme. + */ + getTheme: ( + resolveSystemTheme?: T + ) => T extends true ? 'dark' | 'light' : Theme; + /** + * Sets the current theme. + * @param theme The new theme. One of `dark`, `light` or `system`. + */ + setTheme: (theme: Theme) => void; + /** + * Toggles the current theme. + * + * If the theme is set to `system` (or no theme is set via the root element), + * the theme is set depending on the user's color scheme preference (set in the browser). + */ + toggleTheme: () => void; + /** + * Register an element to act as a toggle! When clicked, it will toggle the theme. + * @param toggle The HTML element that should act as the toggle + */ + registerToggle: (toggle: HTMLElement | null) => void; + /** + * Allows for adding a callback that gets called whenever the theme changes. + * @param callback The callback to be executed + */ + onThemeChange: (callback: ThemeChangeCallback) => void; + /** + * Simply gets the first mutation and calls all registered callbacks. + * @param mutations The mutations array from the observer. Due to the specified options, this will always be a 1-length array, + */ + private themeManagerMutationHandler; + } +} diff --git a/playground/package.json b/playground/package.json index 792d861..1e0b623 100644 --- a/playground/package.json +++ b/playground/package.json @@ -25,6 +25,7 @@ "sharp": "catalog:", "@studiocms/blog": "catalog:", "@studiocms/devapps": "catalog:", + "@studiocms/socialposter": "workspace:*", "@studiocms/wysiwyg": "workspace:*" } } diff --git a/playground/studiocms.config.mjs b/playground/studiocms.config.mjs index 2b78afd..efd037c 100644 --- a/playground/studiocms.config.mjs +++ b/playground/studiocms.config.mjs @@ -1,12 +1,18 @@ import blog from '@studiocms/blog'; import WYSIWYG from '@studiocms/wysiwyg'; import WYSIWYGStudio from '@studiocms/wysiwyg/studio'; +import socialPoster from '@studiocms/socialposter'; import { defineStudioCMSConfig } from 'studiocms/config'; export default defineStudioCMSConfig({ dbStartPage: false, verbose: true, - plugins: [blog(), WYSIWYGStudio({ licenseKey: 'LICENSE' }), WYSIWYG()], + plugins: [ + blog(), + WYSIWYGStudio({ licenseKey: 'LICENSE' }), + WYSIWYG(), + socialPoster({ bluesky: true, threads: true, twitter: true }), + ], dashboardConfig: { developerConfig: { demoMode: false, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 952d2cd..fc9db8d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,11 +13,11 @@ catalogs: specifier: ^9.1.2 version: 9.1.3 '@studiocms/blog': - specifier: 0.1.0-beta.13 - version: 0.1.0-beta.13 + specifier: 0.1.0-beta.14 + version: 0.1.0-beta.14 '@studiocms/devapps': - specifier: 0.1.0-beta.13 - version: 0.1.0-beta.13 + specifier: 0.1.0-beta.14 + version: 0.1.0-beta.14 '@types/node': specifier: ^22.0.0 version: 22.13.13 @@ -31,8 +31,8 @@ catalogs: specifier: ^0.33.5 version: 0.33.5 studiocms: - specifier: 0.1.0-beta.13 - version: 0.1.0-beta.13 + specifier: 0.1.0-beta.14 + version: 0.1.0-beta.14 typescript: specifier: ^5.7 version: 5.8.2 @@ -41,8 +41,8 @@ catalogs: specifier: ^5.5 version: 5.5.5 studiocms: - specifier: 0.1.0-beta.13 - version: 0.1.0-beta.13 + specifier: 0.1.0-beta.14 + version: 0.1.0-beta.14 vite: specifier: ^6.2.0 version: 6.2.3 @@ -103,6 +103,37 @@ importers: specifier: ^4.1.3 version: 4.1.3(@types/node@22.13.13)(typescript@5.8.2) + packages/studiocms_socialposter: + dependencies: + '@atproto/api': + specifier: ^0.14.20 + version: 0.14.20 + '@studiocms/ui': + specifier: ^0.4.16 + version: 0.4.16(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0)) + astro: + specifier: catalog:min + version: 5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2) + astro-integration-kit: + specifier: 'catalog:' + version: 0.18.0(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2)) + quill: + specifier: ^2.0.3 + version: 2.0.3 + studiocms: + specifier: catalog:min + version: 0.1.0-beta.14(@astrojs/db@0.14.9(@types/react@19.0.12)(react@19.0.0))(@astrojs/markdown-remark@6.3.1)(@libsql/client@0.15.1)(@types/react@19.0.12)(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(react@19.0.0)(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0)) + twitter-api-v2: + specifier: ^1.22.0 + version: 1.22.0 + vite: + specifier: catalog:min + version: 6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0) + devDependencies: + '@types/node': + specifier: 'catalog:' + version: 22.13.13 + packages/studiocms_wysiwyg: dependencies: '@grapesjs/studio-sdk': @@ -167,7 +198,7 @@ importers: version: 2.0.1 studiocms: specifier: catalog:min - version: 0.1.0-beta.13(@astrojs/db@0.14.9(@types/react@19.0.12)(react@19.0.0))(@astrojs/markdown-remark@6.3.1)(@libsql/client@0.15.1)(@types/react@19.0.12)(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(react@19.0.0)(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0)) + version: 0.1.0-beta.14(@astrojs/db@0.14.9(@types/react@19.0.12)(react@19.0.0))(@astrojs/markdown-remark@6.3.1)(@libsql/client@0.15.1)(@types/react@19.0.12)(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(react@19.0.0)(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0)) ultrahtml: specifier: ^1.5.3 version: 1.5.3 @@ -189,10 +220,13 @@ importers: version: 9.1.3(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2)) '@studiocms/blog': specifier: 'catalog:' - version: 0.1.0-beta.13(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(studiocms@0.1.0-beta.13(@astrojs/db@0.14.9(@types/react@19.0.12)(react@19.0.0))(@astrojs/markdown-remark@6.3.1)(@libsql/client@0.15.1)(@types/react@19.0.12)(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(react@19.0.0)(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0)))(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0)) + version: 0.1.0-beta.14(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(studiocms@0.1.0-beta.14(@astrojs/db@0.14.9(@types/react@19.0.12)(react@19.0.0))(@astrojs/markdown-remark@6.3.1)(@libsql/client@0.15.1)(@types/react@19.0.12)(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(react@19.0.0)(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0)))(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0)) '@studiocms/devapps': specifier: 'catalog:' - version: 0.1.0-beta.13(@astrojs/db@0.14.9(@types/react@19.0.12)(react@19.0.0))(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(studiocms@0.1.0-beta.13(@astrojs/db@0.14.9(@types/react@19.0.12)(react@19.0.0))(@astrojs/markdown-remark@6.3.1)(@libsql/client@0.15.1)(@types/react@19.0.12)(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(react@19.0.0)(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0)))(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0)) + version: 0.1.0-beta.14(@astrojs/db@0.14.9(@types/react@19.0.12)(react@19.0.0))(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(studiocms@0.1.0-beta.14(@astrojs/db@0.14.9(@types/react@19.0.12)(react@19.0.0))(@astrojs/markdown-remark@6.3.1)(@libsql/client@0.15.1)(@types/react@19.0.12)(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(react@19.0.0)(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0)))(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0)) + '@studiocms/socialposter': + specifier: workspace:* + version: link:../packages/studiocms_socialposter '@studiocms/wysiwyg': specifier: workspace:* version: link:../packages/studiocms_wysiwyg @@ -204,7 +238,7 @@ importers: version: 0.33.5 studiocms: specifier: 'catalog:' - version: 0.1.0-beta.13(@astrojs/db@0.14.9(@types/react@19.0.12)(react@19.0.0))(@astrojs/markdown-remark@6.3.1)(@libsql/client@0.15.1)(@types/react@19.0.12)(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(react@19.0.0)(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0)) + version: 0.1.0-beta.14(@astrojs/db@0.14.9(@types/react@19.0.12)(react@19.0.0))(@astrojs/markdown-remark@6.3.1)(@libsql/client@0.15.1)(@types/react@19.0.12)(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(react@19.0.0)(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0)) devDependencies: '@types/node': specifier: 'catalog:' @@ -250,6 +284,21 @@ packages: resolution: {integrity: sha512-wxhSKRfKugLwLlr4OFfcqovk+LIFtKwLyGPqMsv+9/ibqqnW3Gv7tBhtKEb0gAyUAC4G9BTVQeQahqnQAhd6IQ==} engines: {node: ^18.17.1 || ^20.3.0 || >=22.0.0} + '@atproto/api@0.14.20': + resolution: {integrity: sha512-Daip22+u9N+EVPk9PsEEVrTfjIqGczXnAT7o2EHGd0JsOzMbp3a6wmW1beKqYDzPf+Dc36/39JeUYYqhB3fKjg==} + + '@atproto/common-web@0.4.1': + resolution: {integrity: sha512-Ghh+djHYMAUCktLKwr2IuGgtjcwSWGudp+K7+N7KBA9pDDloOXUEY8Agjc5SHSo9B1QIEFkegClU5n+apn2e0w==} + + '@atproto/lexicon@0.4.10': + resolution: {integrity: sha512-uDbP20vetBgtXPuxoyRcvOGBt2gNe1dFc9yYKcb6jWmXfseHiGTnIlORJOLBXIT2Pz15Eap4fLxAu6zFAykD5A==} + + '@atproto/syntax@0.4.0': + resolution: {integrity: sha512-b9y5ceHS8YKOfP3mdKmwAx5yVj9294UN7FG2XzP6V5aKUdFazEYRnR9m5n5ZQFKa3GNvz7de9guZCJ/sUTcOAA==} + + '@atproto/xrpc@0.6.12': + resolution: {integrity: sha512-Ut3iISNLujlmY9Gu8sNU+SPDJDvqlVzWddU8qUr0Yae5oD4SguaUFjjhireMGhQ3M5E0KljQgDbTmnBo1kIZ3w==} + '@babel/code-frame@7.26.2': resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} engines: {node: '>=6.9.0'} @@ -1275,11 +1324,6 @@ packages: '@manypkg/get-packages@1.1.3': resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} - '@matthiesenxyz/integration-utils@0.3.0': - resolution: {integrity: sha512-i0Cw7iH0H6YfcFny/lss/ZtgAX8eqDeMWzhvmgMIWlxgZAsrRdnI7BWiTHpjb3aMdLLsXEcY3vnQ+RaSQaaW8Q==} - peerDependencies: - astro: ^4.14 || ^5 - '@mixmark-io/domino@2.2.0': resolution: {integrity: sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==} @@ -1396,18 +1440,6 @@ packages: '@oslojs/jwt@0.2.0': resolution: {integrity: sha512-bLE7BtHrURedCn4Mco3ma9L4Y1GR2SMBuIvjWr7rmQ4/W/4Jy70TIAgZ+0nIlk0xHz1vNP8x8DCns45Sb2XRbg==} - '@pnpm/config.env-replace@1.1.0': - resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} - engines: {node: '>=12.22.0'} - - '@pnpm/network.ca-file@1.0.2': - resolution: {integrity: sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==} - engines: {node: '>=12.22.0'} - - '@pnpm/npm-conf@2.3.1': - resolution: {integrity: sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==} - engines: {node: '>=12'} - '@rollup/pluginutils@5.1.4': resolution: {integrity: sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==} engines: {node: '>=14.0.0'} @@ -1555,19 +1587,19 @@ packages: engines: {node: '>=8.10'} hasBin: true - '@studiocms/blog@0.1.0-beta.13': - resolution: {integrity: sha512-sTiiZFLftFNIUECAaidGulwp+/Koim0u6ebuOwZmAuG2Yj1MJQ+dD9SOQFSwAs6ZeBw+ygJn2hiy8/aHAMAGEg==} + '@studiocms/blog@0.1.0-beta.14': + resolution: {integrity: sha512-wyNPXBlkPCXO30dG0WxWmwSnlCuuA5YL2IEKVvKe3YEXC6SkOjXl2b8euZwU/dWZhkZqj/fD5/tdloPxHEY8ow==} peerDependencies: astro: ^5.5.0 - studiocms: 0.1.0-beta.13 + studiocms: 0.1.0-beta.14 vite: ^6.2.0 - '@studiocms/devapps@0.1.0-beta.13': - resolution: {integrity: sha512-5gPrusLYa9KICMpH8Xg4Wrin3HIIMpgfZ+I3i1Er9TQpIaf7QktoPMKR4ppZYFwNi81QNBnzrk0mSDFqsunvzg==} + '@studiocms/devapps@0.1.0-beta.14': + resolution: {integrity: sha512-RJJAU2APZCfdJmDUvxxXh1EwhHkmsDp39qwVth9ScA8L3/GmtXqsPnSXDP/NAPbraq/t3GuykshRLaloz730sg==} peerDependencies: '@astrojs/db': ^0.14.7 astro: ^5.5.0 - studiocms: 0.1.0-beta.13 + studiocms: 0.1.0-beta.14 vite: ^6.2.0 peerDependenciesMeta: studiocms: @@ -1939,11 +1971,6 @@ packages: resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} engines: {node: '>=4'} - astro-integration-kit@0.17.0: - resolution: {integrity: sha512-fe31CCKmrGYn/kkBd1J4b7P02gEdMdEIFBz14zdAud+YAmJeLtZD6wmrCz3LDau+lE1oM1hQnvmZXVSM/YveKw==} - peerDependencies: - astro: ^4.12.0 || ^5.0.0-beta - astro-integration-kit@0.18.0: resolution: {integrity: sha512-Z0QW5IQjosuKQDEGYYkvUX6EhEtrmE4/oViqWz23QveV8U7AuyFsTdg00WRNPevWZl/5a4lLUeDpv4bCRynRRg==} peerDependencies: @@ -1963,6 +1990,9 @@ packages: resolution: {integrity: sha512-TkOhqze98lP+6e7SPbrBpyhTpfvqqX8VYKGn4uckrgPan4WQIHnTaUD2zZzZS18eVVDj4rHPcIZa1PGgvo1DfA==} engines: {node: '>= 14'} + await-lock@2.2.2: + resolution: {integrity: sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw==} + axobject-query@4.1.0: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} @@ -2054,9 +2084,6 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true - buffer-equal-constant-time@1.0.1: - resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} - buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} @@ -2280,9 +2307,6 @@ packages: confbox@0.1.8: resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} - config-chain@1.1.13: - resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} - connect-history-api-fallback@2.0.0: resolution: {integrity: sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==} engines: {node: '>=0.8'} @@ -2386,10 +2410,6 @@ packages: deep-diff@1.0.2: resolution: {integrity: sha512-aWS3UIVH+NPGCD1kki+DCU9Dua032iSsO43LqQpcs4R3+dVv7tX0qBGjiVHJHjplsoUM2XRO/KB92glqc68awg==} - deep-extend@0.6.0: - resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} - engines: {node: '>=4.0.0'} - default-browser-id@5.0.0: resolution: {integrity: sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==} engines: {node: '>=18'} @@ -2631,9 +2651,6 @@ packages: easy-table@1.2.0: resolution: {integrity: sha512-OFzVOv03YpvtcWGe5AayU5G2hgybsg3iqA6drU8UaoZyB9jLGMTrz9+asnLp/E+6qPh88yEI1gvyZFZ41dmgww==} - ecdsa-sig-formatter@1.0.11: - resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} - ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} @@ -2789,6 +2806,9 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + fast-glob@3.3.3: resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} @@ -2973,9 +2993,6 @@ packages: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} - graceful-fs@4.2.10: - resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} - graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -3029,6 +3046,9 @@ packages: grapesjs@0.22.6: resolution: {integrity: sha512-V4sD0jDhE95bz3bwC3gD+DmZzelwgozlarcFrEQFGv7HwYmKOIVXni7i8NVj/DLRGCD5jVHmr4k/sV5oSXPajw==} + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + grapick@0.1.13: resolution: {integrity: sha512-2v7DdmXKbl9+GsL2ZRl2qEMD+PeczYJBSifwx+5SGbaSh0pZ+b6GLya87cBfN953wwXsZqyzuSVPBzqRz8F12g==} @@ -3223,9 +3243,6 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - ini@1.3.8: - resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - inquirer@8.2.6: resolution: {integrity: sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==} engines: {node: '>=12.0.0'} @@ -3368,6 +3385,9 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + iso-datestring-validator@2.2.2: + resolution: {integrity: sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA==} + isobject@3.0.1: resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} engines: {node: '>=0.10.0'} @@ -3421,16 +3441,6 @@ packages: jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} - jsonwebtoken@9.0.2: - resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} - engines: {node: '>=12', npm: '>=6'} - - jwa@1.4.1: - resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==} - - jws@3.2.2: - resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} - katex@0.16.21: resolution: {integrity: sha512-XvqR7FgOHtWupfMiigNzmh+MgUVmDGU2kXZm899ZkPfcuoPuFxyHmXsgATDpFZDAXCI8tvinaVcDo8PIIJSo4A==} hasBin: true @@ -3455,16 +3465,11 @@ packages: '@types/node': '>=18' typescript: '>=5.0.4' - ky@1.7.5: - resolution: {integrity: sha512-HzhziW6sc5m0pwi5M196+7cEBtbt0lCYi67wNsiwMUmz833wloE0gbzJPWKs1gliFKQb34huItDQX97LyOdPdA==} - engines: {node: '>=18'} - launch-editor@2.10.0: resolution: {integrity: sha512-D7dBRJo/qcGX9xlvt/6wUYzQxjh5G1RvZPgPv8vi4KRU99DVQL/oW7tnVOCCTm2HGeo3C5HvGE5Yrh6UBoZ0vA==} libsql@0.5.3: resolution: {integrity: sha512-S3WR8WNCJV1VXraBFUKjDA6+8LcNDJMLm+83qohm1O3YM1iVqV2+/XN3SXOxpxVjuL4g/rLrjO5kzygkPefCFQ==} - cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] listr-silent-renderer@1.1.1: @@ -3497,32 +3502,21 @@ packages: resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + lodash-es@4.17.21: + resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + lodash._reinterpolate@3.0.0: resolution: {integrity: sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==} + lodash.clonedeep@4.5.0: + resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==} + lodash.debounce@4.0.8: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} - lodash.includes@4.3.0: - resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} - - lodash.isboolean@3.0.3: - resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} - - lodash.isinteger@4.0.4: - resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} - - lodash.isnumber@3.0.3: - resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==} - - lodash.isplainobject@4.0.6: - resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} - - lodash.isstring@4.0.1: - resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} - - lodash.once@4.1.1: - resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} + lodash.isequal@4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead. lodash.startcase@4.4.0: resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} @@ -3797,6 +3791,9 @@ packages: resolution: {integrity: sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==} hasBin: true + multiformats@9.9.0: + resolution: {integrity: sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==} + mute-stream@0.0.8: resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} @@ -4001,10 +3998,6 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} - package-json@10.0.1: - resolution: {integrity: sha512-ua1L4OgXSBdsu1FPb7F3tYH0F48a6kxvod4pLUlGY9COeJAJQNX/sNH2IiEmsxw7lqYiAwrdHMjz1FctOsyDQg==} - engines: {node: '>=18'} - package-manager-detector@0.2.11: resolution: {integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==} @@ -4014,6 +4007,9 @@ packages: param-case@3.0.4: resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} + parchment@3.0.0: + resolution: {integrity: sha512-HUrJFQ/StvgmXRcQ1ftY6VEZUq3jA2t9ncFN4F84J/vN0/FPpQF+8FKXb3l6fLces6q0uOHj6NJn+2xvZnxO6A==} + parse-latin@7.0.0: resolution: {integrity: sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==} @@ -4172,9 +4168,6 @@ packages: prosemirror-view@1.38.1: resolution: {integrity: sha512-4FH/uM1A4PNyrxXbD+RAbAsf0d/mM0D/wAKSVVWK7o0A9Q/oOXJBrw786mBf2Vnrs/Edly6dH6Z2gsb7zWwaUw==} - proto-list@1.2.4: - resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} - proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -4201,6 +4194,14 @@ packages: resolution: {integrity: sha512-MX8gB7cVYTrYcFfAnfLlhRd0+Toyl8yX8uBx1MrX7K0jegiz9TumwOK27ldXrgDlHRdVi+MqU9Ssw6dr4BNreg==} engines: {node: '>=18'} + quill-delta@5.1.0: + resolution: {integrity: sha512-X74oCeRI4/p0ucjb5Ma8adTXd9Scumz367kkMK5V/IatcX6A0vlgLgKbzXWy5nZmCGeNJm2oQX0d2Eqj+ZIlCA==} + engines: {node: '>= 12.0.0'} + + quill@2.0.3: + resolution: {integrity: sha512-xEYQBqfYx/sfb33VJiKnSJp8ehloavImQ2A6564GAbqG55PGw1dAWUn1MUbQB62t0azawUS2CZZhWCjO8gRvTw==} + engines: {npm: '>=8.2.3'} + radix3@1.1.2: resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} @@ -4215,10 +4216,6 @@ packages: resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} engines: {node: '>= 0.8'} - rc@1.2.8: - resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} - hasBin: true - react-dom@19.0.0: resolution: {integrity: sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==} peerDependencies: @@ -4281,14 +4278,6 @@ packages: resolution: {integrity: sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==} engines: {node: '>=4'} - registry-auth-token@5.1.0: - resolution: {integrity: sha512-GdekYuwLXLxMuFTwAPg5UKGLW/UXzQrZvH/Zj791BQif5T05T0RsaLfHc9q3ZOKi7n+BoprPD9mJ0O0k4xzUlw==} - engines: {node: '>=14'} - - registry-url@6.0.1: - resolution: {integrity: sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==} - engines: {node: '>=12'} - regjsgen@0.8.0: resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} @@ -4668,10 +4657,6 @@ packages: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} - strip-json-comments@2.0.1: - resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} - engines: {node: '>=0.10.0'} - strip-json-comments@5.0.1: resolution: {integrity: sha512-0fk9zBqO67Nq5M/m45qHCJxylV/DhBlIOVExqgOMiCCrzrhU6tCibRXNqE3jwJLftzE9SNuZtYbpzcO+i9FiKw==} engines: {node: '>=14.16'} @@ -4679,8 +4664,8 @@ packages: strnum@1.1.2: resolution: {integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==} - studiocms@0.1.0-beta.13: - resolution: {integrity: sha512-h8iH/DnOh+/qGcvhhauDzorDc+TwHXUnTmf9+LDLzQyDGA3x6Kj649sQNf3etCbUegO4n41t1HcF594gZt5Trw==} + studiocms@0.1.0-beta.14: + resolution: {integrity: sha512-BGwUqhkLUF82qqxEhnGtizwwCBI1EzQdHW1T3W57aMa4KOv0PWzr0pK85GQIMpIbOIcYbN/lV+/Wo5roptfC5g==} hasBin: true peerDependencies: '@astrojs/db': ^0.14.7 @@ -4770,6 +4755,10 @@ packages: resolution: {integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==} engines: {node: '>=12.0.0'} + tlds@1.256.0: + resolution: {integrity: sha512-ZmyVB9DAw+FFTmLElGYJgdZFsKLYd/I59Bg9NHkCGPwAbVZNRilFWDMAdX8UG+bHuv7kfursd5XGqo/9wi26lA==} + hasBin: true + tmp@0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} @@ -4831,6 +4820,9 @@ packages: turndown@7.2.0: resolution: {integrity: sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A==} + twitter-api-v2@1.22.0: + resolution: {integrity: sha512-KlcRL9vcBzjeS/PwxX33NziP+SHp9n35DOclKtpOmnNes7nNVnK7WG4pKlHfBqGrY5kAz/8J5ERS8DWkYOaiWw==} + type-detect@4.1.0: resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==} engines: {node: '>=4'} @@ -4855,6 +4847,9 @@ packages: ufo@1.5.4: resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} + uint8arrays@3.0.0: + resolution: {integrity: sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA==} + ultrahtml@1.5.3: resolution: {integrity: sha512-GykOvZwgDWZlTQMtp5jrD4BVL+gNn2NVlVafjcFUJ7taY20tqYdwdoWBFy6GBJsNTZe1GkGPkSl5knQAjtgceg==} @@ -5405,6 +5400,39 @@ snapshots: transitivePeerDependencies: - supports-color + '@atproto/api@0.14.20': + dependencies: + '@atproto/common-web': 0.4.1 + '@atproto/lexicon': 0.4.10 + '@atproto/syntax': 0.4.0 + '@atproto/xrpc': 0.6.12 + await-lock: 2.2.2 + multiformats: 9.9.0 + tlds: 1.256.0 + zod: 3.24.2 + + '@atproto/common-web@0.4.1': + dependencies: + graphemer: 1.4.0 + multiformats: 9.9.0 + uint8arrays: 3.0.0 + zod: 3.24.2 + + '@atproto/lexicon@0.4.10': + dependencies: + '@atproto/common-web': 0.4.1 + '@atproto/syntax': 0.4.0 + iso-datestring-validator: 2.2.2 + multiformats: 9.9.0 + zod: 3.24.2 + + '@atproto/syntax@0.4.0': {} + + '@atproto/xrpc@0.6.12': + dependencies: + '@atproto/lexicon': 0.4.10 + zod: 3.24.2 + '@babel/code-frame@7.26.2': dependencies: '@babel/helper-validator-identifier': 7.25.9 @@ -6614,13 +6642,6 @@ snapshots: globby: 11.1.0 read-yaml-file: 1.1.0 - '@matthiesenxyz/integration-utils@0.3.0(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))': - dependencies: - astro: 5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2) - astro-integration-kit: 0.17.0(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2)) - package-json: 10.0.1 - semver: 7.7.1 - '@mixmark-io/domino@2.2.0': {} '@nanostores/i18n@0.12.2(nanostores@0.11.4)': @@ -6748,18 +6769,6 @@ snapshots: dependencies: '@oslojs/encoding': 0.4.1 - '@pnpm/config.env-replace@1.1.0': {} - - '@pnpm/network.ca-file@1.0.2': - dependencies: - graceful-fs: 4.2.10 - - '@pnpm/npm-conf@2.3.1': - dependencies: - '@pnpm/config.env-replace': 1.1.0 - '@pnpm/network.ca-file': 1.0.2 - config-chain: 1.1.13 - '@rollup/pluginutils@5.1.4(rollup@4.37.0)': dependencies: '@types/estree': 1.0.7 @@ -6875,15 +6884,15 @@ snapshots: ignore: 5.3.2 p-map: 4.0.0 - '@studiocms/blog@0.1.0-beta.13(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(studiocms@0.1.0-beta.13(@astrojs/db@0.14.9(@types/react@19.0.12)(react@19.0.0))(@astrojs/markdown-remark@6.3.1)(@libsql/client@0.15.1)(@types/react@19.0.12)(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(react@19.0.0)(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0)))(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0))': + '@studiocms/blog@0.1.0-beta.14(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(studiocms@0.1.0-beta.14(@astrojs/db@0.14.9(@types/react@19.0.12)(react@19.0.0))(@astrojs/markdown-remark@6.3.1)(@libsql/client@0.15.1)(@types/react@19.0.12)(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(react@19.0.0)(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0)))(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0))': dependencies: '@astrojs/rss': 4.0.11 astro: 5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2) astro-integration-kit: 0.18.0(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2)) - studiocms: 0.1.0-beta.13(@astrojs/db@0.14.9(@types/react@19.0.12)(react@19.0.0))(@astrojs/markdown-remark@6.3.1)(@libsql/client@0.15.1)(@types/react@19.0.12)(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(react@19.0.0)(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0)) + studiocms: 0.1.0-beta.14(@astrojs/db@0.14.9(@types/react@19.0.12)(react@19.0.0))(@astrojs/markdown-remark@6.3.1)(@libsql/client@0.15.1)(@types/react@19.0.12)(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(react@19.0.0)(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0)) vite: 6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0) - '@studiocms/devapps@0.1.0-beta.13(@astrojs/db@0.14.9(@types/react@19.0.12)(react@19.0.0))(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(studiocms@0.1.0-beta.13(@astrojs/db@0.14.9(@types/react@19.0.12)(react@19.0.0))(@astrojs/markdown-remark@6.3.1)(@libsql/client@0.15.1)(@types/react@19.0.12)(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(react@19.0.0)(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0)))(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0))': + '@studiocms/devapps@0.1.0-beta.14(@astrojs/db@0.14.9(@types/react@19.0.12)(react@19.0.0))(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(studiocms@0.1.0-beta.14(@astrojs/db@0.14.9(@types/react@19.0.12)(react@19.0.0))(@astrojs/markdown-remark@6.3.1)(@libsql/client@0.15.1)(@types/react@19.0.12)(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(react@19.0.0)(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0)))(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0))': dependencies: '@astrojs/db': 0.14.9(@types/react@19.0.12)(react@19.0.0) astro: 5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2) @@ -6893,7 +6902,7 @@ snapshots: turndown: 7.2.0 vite: 6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0) optionalDependencies: - studiocms: 0.1.0-beta.13(@astrojs/db@0.14.9(@types/react@19.0.12)(react@19.0.0))(@astrojs/markdown-remark@6.3.1)(@libsql/client@0.15.1)(@types/react@19.0.12)(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(react@19.0.0)(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0)) + studiocms: 0.1.0-beta.14(@astrojs/db@0.14.9(@types/react@19.0.12)(react@19.0.0))(@astrojs/markdown-remark@6.3.1)(@libsql/client@0.15.1)(@types/react@19.0.12)(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(react@19.0.0)(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0)) '@studiocms/markdown-remark-processor@1.2.0': dependencies: @@ -7304,12 +7313,6 @@ snapshots: dependencies: tslib: 2.8.1 - astro-integration-kit@0.17.0(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2)): - dependencies: - astro: 5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2) - pathe: 1.1.2 - recast: 0.23.11 - astro-integration-kit@0.18.0(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2)): dependencies: astro: 5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2) @@ -7419,6 +7422,8 @@ snapshots: async-listen@3.1.0: {} + await-lock@2.2.2: {} + axobject-query@4.1.0: {} babel-loader@9.2.1(@babel/core@7.26.10)(webpack@5.98.0(webpack-cli@5.1.4)): @@ -7540,8 +7545,6 @@ snapshots: node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.24.4) - buffer-equal-constant-time@1.0.1: {} - buffer-from@1.1.2: {} buffer@5.7.1: @@ -7765,11 +7768,6 @@ snapshots: confbox@0.1.8: {} - config-chain@1.1.13: - dependencies: - ini: 1.3.8 - proto-list: 1.2.4 - connect-history-api-fallback@2.0.0: {} content-disposition@0.5.4: @@ -7852,8 +7850,6 @@ snapshots: deep-diff@1.0.2: {} - deep-extend@0.6.0: {} - default-browser-id@5.0.0: {} default-browser@5.2.1: @@ -8002,10 +7998,6 @@ snapshots: optionalDependencies: wcwidth: 1.0.1 - ecdsa-sig-formatter@1.0.11: - dependencies: - safe-buffer: 5.2.1 - ee-first@1.1.1: {} electron-to-chromium@1.5.128: {} @@ -8182,6 +8174,8 @@ snapshots: fast-deep-equal@3.1.3: {} + fast-diff@1.3.0: {} + fast-glob@3.3.3: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -8363,8 +8357,6 @@ snapshots: gopd@1.2.0: {} - graceful-fs@4.2.10: {} - graceful-fs@4.2.11: {} grapesjs-blocks-basic@1.0.2: {} @@ -8451,6 +8443,8 @@ snapshots: promise-polyfill: 8.3.0 underscore: 1.13.1 + graphemer@1.4.0: {} + grapick@0.1.13: {} h3@1.15.1: @@ -8712,8 +8706,6 @@ snapshots: inherits@2.0.4: {} - ini@1.3.8: {} - inquirer@8.2.6: dependencies: ansi-escapes: 4.3.2 @@ -8827,6 +8819,8 @@ snapshots: isexe@2.0.0: {} + iso-datestring-validator@2.2.2: {} + isobject@3.0.1: {} jest-worker@27.5.1: @@ -8866,30 +8860,6 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 - jsonwebtoken@9.0.2: - dependencies: - jws: 3.2.2 - lodash.includes: 4.3.0 - lodash.isboolean: 3.0.3 - lodash.isinteger: 4.0.4 - lodash.isnumber: 3.0.3 - lodash.isplainobject: 4.0.6 - lodash.isstring: 4.0.1 - lodash.once: 4.1.1 - ms: 2.1.3 - semver: 7.7.1 - - jwa@1.4.1: - dependencies: - buffer-equal-constant-time: 1.0.1 - ecdsa-sig-formatter: 1.0.11 - safe-buffer: 5.2.1 - - jws@3.2.2: - dependencies: - jwa: 1.4.1 - safe-buffer: 5.2.1 - katex@0.16.21: dependencies: commander: 8.3.0 @@ -8921,8 +8891,6 @@ snapshots: zod: 3.24.2 zod-validation-error: 3.4.0(zod@3.24.2) - ky@1.7.5: {} - launch-editor@2.10.0: dependencies: picocolors: 1.1.1 @@ -8987,23 +8955,15 @@ snapshots: dependencies: p-locate: 6.0.0 - lodash._reinterpolate@3.0.0: {} - - lodash.debounce@4.0.8: {} - - lodash.includes@4.3.0: {} - - lodash.isboolean@3.0.3: {} + lodash-es@4.17.21: {} - lodash.isinteger@4.0.4: {} - - lodash.isnumber@3.0.3: {} + lodash._reinterpolate@3.0.0: {} - lodash.isplainobject@4.0.6: {} + lodash.clonedeep@4.5.0: {} - lodash.isstring@4.0.1: {} + lodash.debounce@4.0.8: {} - lodash.once@4.1.1: {} + lodash.isequal@4.5.0: {} lodash.startcase@4.4.0: {} @@ -9443,6 +9403,8 @@ snapshots: dns-packet: 5.6.1 thunky: 1.1.0 + multiformats@9.9.0: {} + mute-stream@0.0.8: {} nanoid@3.3.11: {} @@ -9624,13 +9586,6 @@ snapshots: p-try@2.2.0: {} - package-json@10.0.1: - dependencies: - ky: 1.7.5 - registry-auth-token: 5.1.0 - registry-url: 6.0.1 - semver: 7.7.1 - package-manager-detector@0.2.11: dependencies: quansync: 0.2.10 @@ -9642,6 +9597,8 @@ snapshots: dot-case: 3.0.4 tslib: 2.8.1 + parchment@3.0.0: {} + parse-latin@7.0.0: dependencies: '@types/nlcst': 2.0.3 @@ -9819,8 +9776,6 @@ snapshots: prosemirror-state: 1.4.3 prosemirror-transform: 1.10.3 - proto-list@1.2.4: {} - proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 @@ -9851,6 +9806,19 @@ snapshots: quick-lru@7.0.0: {} + quill-delta@5.1.0: + dependencies: + fast-diff: 1.3.0 + lodash.clonedeep: 4.5.0 + lodash.isequal: 4.5.0 + + quill@2.0.3: + dependencies: + eventemitter3: 5.0.1 + lodash-es: 4.17.21 + parchment: 3.0.0 + quill-delta: 5.1.0 + radix3@1.1.2: {} randombytes@2.1.0: @@ -9866,13 +9834,6 @@ snapshots: iconv-lite: 0.4.24 unpipe: 1.0.0 - rc@1.2.8: - dependencies: - deep-extend: 0.6.0 - ini: 1.3.8 - minimist: 1.2.8 - strip-json-comments: 2.0.1 - react-dom@19.0.0(react@19.0.0): dependencies: react: 19.0.0 @@ -9952,14 +9913,6 @@ snapshots: unicode-match-property-ecmascript: 2.0.0 unicode-match-property-value-ecmascript: 2.2.0 - registry-auth-token@5.1.0: - dependencies: - '@pnpm/npm-conf': 2.3.1 - - registry-url@6.0.1: - dependencies: - rc: 1.2.8 - regjsgen@0.8.0: {} regjsparser@0.12.0: @@ -10477,13 +10430,11 @@ snapshots: strip-final-newline@2.0.0: {} - strip-json-comments@2.0.1: {} - strip-json-comments@5.0.1: {} strnum@1.1.2: {} - studiocms@0.1.0-beta.13(@astrojs/db@0.14.9(@types/react@19.0.12)(react@19.0.0))(@astrojs/markdown-remark@6.3.1)(@libsql/client@0.15.1)(@types/react@19.0.12)(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(react@19.0.0)(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0)): + studiocms@0.1.0-beta.14(@astrojs/db@0.14.9(@types/react@19.0.12)(react@19.0.0))(@astrojs/markdown-remark@6.3.1)(@libsql/client@0.15.1)(@types/react@19.0.12)(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2))(react@19.0.0)(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0)): dependencies: '@astrojs/db': 0.14.9(@types/react@19.0.12)(react@19.0.0) '@astrojs/markdown-remark': 6.3.1 @@ -10496,7 +10447,6 @@ snapshots: '@iconify-json/simple-icons': 1.2.29 '@inox-tools/inline-mod': 2.0.3(vite@6.2.3(@types/node@22.13.13)(jiti@2.4.2)(terser@5.39.0)) '@inox-tools/runtime-logger': 0.4.2(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2)) - '@matthiesenxyz/integration-utils': 0.3.0(astro@5.5.5(@types/node@22.13.13)(jiti@2.4.2)(rollup@4.37.0)(terser@5.39.0)(typescript@5.8.2)) '@nanostores/i18n': 0.12.2(nanostores@0.11.4) '@nanostores/persistent': 0.10.2(nanostores@0.11.4) '@oslojs/binary': 1.0.0 @@ -10520,7 +10470,6 @@ snapshots: figlet: 1.8.0 fuse.js: 7.1.0 is-unicode-supported: 2.1.0 - jsonwebtoken: 9.0.2 katex: 0.16.21 lodash: 4.17.21 mdast-util-from-markdown: 2.0.2 @@ -10529,7 +10478,6 @@ snapshots: mrmime: 2.0.1 nanostores: 0.11.4 nodemailer: 6.10.0 - package-json: 10.0.1 semver: 7.7.1 slice-ansi: 7.1.0 socks: 2.8.4 @@ -10628,6 +10576,8 @@ snapshots: fdir: 6.4.3(picomatch@4.0.2) picomatch: 4.0.2 + tlds@1.256.0: {} + tmp@0.0.33: dependencies: os-tmpdir: 1.0.2 @@ -10684,6 +10634,8 @@ snapshots: dependencies: '@mixmark-io/domino': 2.2.0 + twitter-api-v2@1.22.0: {} + type-detect@4.1.0: {} type-fest@0.21.3: {} @@ -10699,6 +10651,10 @@ snapshots: ufo@1.5.4: {} + uint8arrays@3.0.0: + dependencies: + multiformats: 9.9.0 + ultrahtml@1.5.3: {} uncrypto@0.1.3: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index b9a0d4c..f862fc7 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -2,20 +2,20 @@ catalog: '@astrojs/db': ^0.14.8 '@astrojs/check': ^0.9.4 '@astrojs/node': ^9.1.2 - '@studiocms/blog': 0.1.0-beta.13 - '@studiocms/devapps': 0.1.0-beta.13 + '@studiocms/blog': 0.1.0-beta.14 + '@studiocms/devapps': 0.1.0-beta.14 '@types/node': ^22.0.0 astro: ^5.5 astro-integration-kit: ^0.18 sharp: ^0.33.5 - studiocms: 0.1.0-beta.13 + studiocms: 0.1.0-beta.14 typescript: ^5.7 vite: ^6.2.5 catalogs: min: astro: ^5.5 - studiocms: 0.1.0-beta.13 + studiocms: 0.1.0-beta.14 '@astrojs/db': ^0.14.7 vite: ^6.2.0