From 983df9475d21fb4e382a2c537f4b6208c0bcd00a Mon Sep 17 00:00:00 2001 From: Robert Means Date: Mon, 2 Jun 2025 05:30:15 -0400 Subject: [PATCH 1/8] initial commit --- .../.vitepress/components/AposApiExplorer.vue | 28 + docs/.vitepress/theme/index.js | 2 + docs/public/apostrophecms-openapi.yaml | 5174 +++++++++++++++++ docs/reference/api/api-explorer.md | 117 + docs/reference/api/sandbox.md | 38 + package-lock.json | 17 + package.json | 3 +- 7 files changed, 5378 insertions(+), 1 deletion(-) create mode 100644 docs/.vitepress/components/AposApiExplorer.vue create mode 100644 docs/public/apostrophecms-openapi.yaml create mode 100644 docs/reference/api/api-explorer.md create mode 100644 docs/reference/api/sandbox.md diff --git a/docs/.vitepress/components/AposApiExplorer.vue b/docs/.vitepress/components/AposApiExplorer.vue new file mode 100644 index 00000000..85511426 --- /dev/null +++ b/docs/.vitepress/components/AposApiExplorer.vue @@ -0,0 +1,28 @@ + + + + + \ No newline at end of file diff --git a/docs/.vitepress/theme/index.js b/docs/.vitepress/theme/index.js index b528ae2e..9f8e631a 100644 --- a/docs/.vitepress/theme/index.js +++ b/docs/.vitepress/theme/index.js @@ -17,6 +17,7 @@ import { createEventBus } from './eventBus'; import AposTutorialFilter from '../components/AposTutorialFilter.vue'; import { setupUpdateChecker } from '../helpers/updateChecker'; import { setupYouTubeTracking } from '../helpers/youtubeTracking'; +import AposApiExplorer from '../components/AposApiExplorer.vue' export const eventBus = createEventBus(); export default { @@ -40,6 +41,7 @@ export default { app.component('AposTwoColumns', AposTwoColumns); app.component('AposCtaButton', AposCtaButton); app.component('AposTutorialFilter', AposTutorialFilter); + app.component('AposApiExplorer', AposApiExplorer); if (typeof window !== 'undefined') { setupUpdateChecker(); } diff --git a/docs/public/apostrophecms-openapi.yaml b/docs/public/apostrophecms-openapi.yaml new file mode 100644 index 00000000..9ce4f4df --- /dev/null +++ b/docs/public/apostrophecms-openapi.yaml @@ -0,0 +1,5174 @@ +openapi: 3.0.3 +info: + title: ApostropheCMS REST API + description: | + **For production use:** Download this YAML file and update the server URL + and cookie names to match your setup. + + The ApostropheCMS REST API allows you to create, read, update, and delete content programmatically. + + ## Content Architecture + ApostropheCMS uses a flexible "pieces" system for content types. While the core system provides + essential pieces like users and global content, most projects define custom piece types like + articles, events, or products using the `@apostrophecms/piece-type` module. + + ## Built-in Piece Types + - `@apostrophecms/user` - User accounts and profiles + - `@apostrophecms/global` - Site-wide content (customizable with additional fields) + - `@apostrophecms/image` - Image file management + - `@apostrophecms/file` - General file management (PDFs, documents, etc.) + + ## Built-in Tag Types + - `@apostrophecms/image-tag` - Tags for organizing images + - `@apostrophecms/file-tag` - Tags for organizing files + + ## Common Custom Piece Types + The examples in this API documentation use common piece types that projects typically implement: + - `article` - Blog posts and content pages + - `event` - Calendar events and announcements + + *Note: Custom piece types are defined in your project configuration and follow the same API patterns.* + + ## Authentication + Most endpoints require authentication via session cookies or API keys. + + ## Rate Limiting + API requests are rate-limited to prevent abuse. See response headers for current limits. + + version: 4.0.0 + contact: + name: ApostropheCMS Support + url: https://apostrophecms.com + email: support@apostrophecms.com + license: + name: MIT + url: https://github.com/apostrophecms/apostrophe/blob/main/LICENSE.md + +servers: + - url: https://your-site.com/api/v1 + description: Production server (not for online use) + - url: http://localhost:3000/api/v1 + description: Development server + +components: + securitySchemes: + ApiKeyAuth: + type: apiKey + in: query + name: apikey + description: | + API key for server-to-server communication. + Use as query parameter: ?apikey=your-api-key-here + + Configure in app.js: + ```javascript + '@apostrophecms/express': { + options: { + apiKeys: { + 'myapikey1029384756': { role: 'admin' } + } + } + } + ``` + + BearerAuth: + type: http + scheme: bearer + description: | + ⚠️ **Security Note:** Only use test credentials in this online sandbox. + Real credentials should never be entered in public documentation. + + Bearer token authentication (recommended for API clients). + + **Step 1:** Use the `POST /@apostrophecms/login/login` endpoint below with: + ```json + { + "username": "your-username", + "password": "your-password" + } + ``` + + **Step 2:** Copy **only the token value** from the response (not the full JSON) + Example: if response is `{"token": "abc123"}`, paste only `abc123` + The token will be sent as: Authorization: Bearer {your-token} + + SessionAuth: + type: apiKey + in: cookie + name: project-shortname.sid + description: | + ⚠️ **For testing after download only:** Change "project-shortname" in the `SessionAuth` to your actual + ApostropheCMS shortname (e.g., "myapp.sid"). + + 💡 This authentication won't work when testing in the online ApostropheCMS sandbox. However, you can use the login route to set a cookie you can examine in your browser DevTools. + It will be named `project-shortname.sid`. + + **Step 1:** Use the `POST /@apostrophecms/login/login` endpoint below with: + ```json + { + "username": "your-username", + "password": "your-password", + "session": true + } + ``` + + **Step 2:** Copy the session cookie value from your browser's dev tools + and paste it into the "Value" field above. + + parameters: + Page: + name: page + in: query + description: Page number for pagination + required: false + schema: + type: integer + minimum: 1 + default: 1 + + PerPage: + name: perPage + in: query + description: Number of items per page + required: false + schema: + type: integer + minimum: 1 + maximum: 100 + default: 10 + + Search: + name: search + in: query + description: Search term for filtering results + required: false + schema: + type: string + + Autocomplete: + name: autocomplete + in: query + description: Partial word search for autocomplete functionality + required: false + schema: + type: string + + AposMode: + name: aposMode + in: query + description: Request draft or published version + required: false + schema: + type: string + enum: [draft, published] + default: published + + AposLocale: + name: aposLocale + in: query + description: Locale for internationalization + required: false + schema: + type: string + example: "fr" + + RenderAreas: + name: render-areas + in: query + description: Render area content as HTML instead of returning widget data + required: false + schema: + type: boolean + default: false + + PageId: + name: _id + in: path + required: true + description: Page document ID (can include mode and locale, e.g., id:en:published) + schema: + type: string + example: "ckitdo5oq004pu69kr6oxo6fr:en:published" + + AllPages: + name: all + in: query + description: Include entire page tree regardless of depth + schema: + type: string + enum: ["1"] + example: "1" + + FlatResponse: + name: flat + in: query + description: Return pages in flat array instead of tree structure + schema: + type: string + enum: ["1"] + example: "1" + + ChildrenParam: + name: children + in: query + description: Include children array in response + schema: + type: string + enum: ["false"] + example: "false" + + schemas: + PageTreeResponse: + type: object + description: Home page with nested children structure + properties: + _id: + type: string + description: Unique document identifier + example: "ckhdscx5900054z9k88uqs16w" + orphan: + type: boolean + description: Whether page is excluded from navigation + example: false + visibility: + type: string + enum: [public, loginRequired, private] + description: Page visibility setting + example: "public" + type: + type: string + description: Page type identifier + example: "@apostrophecms/home-page" + title: + type: string + description: Page title + example: "Home Page" + slug: + type: string + description: URL slug for the page + example: "/" + rank: + type: integer + description: Order among sibling pages + example: 0 + level: + type: integer + description: Page tree depth level + example: 0 + path: + type: string + description: Ancestor path of page IDs + example: "ckhdscx5900054z9k88uqs16w" + _url: + type: string + format: uri + description: Complete page URL + example: "http://localhost:3000/" + _ancestors: + type: array + items: + $ref: '#/components/schemas/PageSummary' + description: Array of ancestor pages + _children: + type: array + items: + $ref: '#/components/schemas/PageTreeResponse' + description: Array of child pages + createdAt: + type: string + format: date-time + description: ISO date of creation + updatedAt: + type: string + format: date-time + description: ISO date of last update + archived: + type: boolean + description: Whether page is archived + example: false + historicUrls: + type: array + items: + type: string + description: Previous URLs that redirect to this page + metaType: + type: string + example: "doc" + titleSortified: + type: string + description: Sortable version of title + updatedBy: + $ref: '#/components/schemas/User' + _edit: + type: boolean + description: Edit permission flag + + FlatPageResponse: + type: object + properties: + results: + type: array + items: + allOf: + - $ref: '#/components/schemas/PageTreeResponse' + - type: object + properties: + _children: + type: array + items: + type: string + description: Array of child page IDs (in flat response) + _ancestors: + type: array + items: + type: string + description: Array of ancestor page IDs (in flat response) + + PageSummary: + type: object + description: Abbreviated page information for ancestors/references + properties: + _id: + type: string + title: + type: string + slug: + type: string + type: + type: string + _url: + type: string + format: uri + level: + type: integer + rank: + type: integer + + PageCreateRequest: + type: object + required: + - _targetId + - _position + - title + properties: + _targetId: + type: string + description: ID of target page for positioning (_home and _archive are convenience values) + example: "ckhdscx5900054z9k88uqs16w" + _position: + oneOf: + - type: string + enum: [before, after, firstChild, lastChild] + - type: integer + minimum: 0 + description: Position relative to target (string values) or child index (number) + example: "firstChild" + _copyingId: + type: string + description: Optional ID of existing page to copy properties from + title: + type: string + description: Page title + example: "My New Page" + slug: + type: string + description: URL slug (auto-generated if not provided) + example: "/my-new-page" + type: + type: string + description: Page type + example: "default-page" + visibility: + type: string + enum: [public, loginRequired, private] + default: public + # Add other fields based on your page types + + PageUpdateRequest: + type: object + properties: + _targetId: + type: string + description: ID of target page for repositioning (required if moving page) + _position: + oneOf: + - type: string + enum: [before, after, firstChild, lastChild] + - type: integer + minimum: 0 + description: New position (required if moving page) + title: + type: string + description: Updated page title + slug: + type: string + description: Updated URL slug + visibility: + type: string + enum: [public, loginRequired, private] + updatedBy: + $ref: '#/components/schemas/User' + + Area: + type: object + description: Content area containing widgets + properties: + _id: + type: string + example: "ckj0k0dy7000i2a68s1z8v4ky" # Add examples + metaType: + type: string + enum: [area] # Make it an enum for precision + example: "area" + items: + type: array + description: "Array of widgets within this area" # Add description + items: + $ref: '#/components/schemas/Widget' + _edit: + type: boolean + description: "Whether area is in edit mode" # Document this important property + _docId: + type: string + example: "ckj0k2i45001c7u9kky3tftx2" + + Widget: + type: object + description: Content widget within an area + properties: + _id: + type: string + metaType: + type: string + enum: [widget] + type: + type: string + example: "@apostrophecms/rich-text" + _edit: + type: boolean + _docId: + type: string + # Rich text widget specific properties + content: + type: string + description: "HTML content for rich text widgets (filtered based on widget configuration)" + example: "

Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.

" + import: + type: object + description: "Import configuration for external content (used during creation/update)" + properties: + baseUrl: + type: string + format: uri + description: "Base URL for resolving relative image URLs" + example: "https://myoldsite.com" + html: + type: string + description: "HTML content to import (images will be automatically imported)" + example: "

Here is some text.

\n" + additionalProperties: true + + # Array Field + ArrayField: + type: array + description: "Array field containing structured data items" + items: + type: object + properties: + _id: + type: string + description: "Automatically generated ID for each array item" + example: "ckj0k15x4001h2a68staejzpj" + additionalProperties: true + example: + _id: "ckj0k15x4001h2a68staejzpj" + label: "The first one" + count: 27 + + # Attachment Field + AttachmentField: + type: object + description: "File attachment with metadata and URLs" + properties: + _id: + type: string + example: "ckhdsopzr0005rt9kn49eyzb5" + crop: + type: string + nullable: true + description: "Crop settings for images" + group: + type: string + description: "File group classification" + example: "images" + createdAt: + type: string + format: date-time + example: "2020-11-11T19:27:11.782Z" + name: + type: string + description: "Original filename without extension" + example: "double-rainbow" + title: + type: string + description: "Display title for the attachment" + example: "double rainbow" + extension: + type: string + description: "File extension" + example: "jpg" + type: + type: string + enum: [attachment] + docIds: + type: array + items: + type: string + description: "Documents that reference this attachment" + archivedDocIds: + type: array + items: + type: string + length: + type: integer + description: "File size in bytes" + example: 644584 + md5: + type: string + description: "MD5 hash of the original file" + example: "f41217031f11e8483ee81e20782f51be" + width: + type: integer + description: "Image width in pixels" + example: 2560 + height: + type: integer + description: "Image height in pixels" + example: 1922 + landscape: + type: boolean + description: "Whether image is in landscape orientation" + used: + type: boolean + description: "Whether attachment is currently used" + utilized: + type: boolean + description: "Whether attachment is utilized" + archived: + type: boolean + description: "Whether attachment is archived" + _urls: + type: object + description: "Available image sizes and URLs (for images only)" + properties: + max: + type: string + format: uri + example: "https://example.net/uploads/attachments/ckhdsopzr0005rt9kn49eyzb5-double-rainbow.max.jpg" + full: + type: string + format: uri + example: "https://example.net/uploads/attachments/ckhdsopzr0005rt9kn49eyzb5-double-rainbow.full.jpg" + two-thirds: + type: string + format: uri + example: "https://example.net/uploads/attachments/ckhdsopzr0005rt9kn49eyzb5-double-rainbow.two-thirds.jpg" + one-half: + type: string + format: uri + example: "https://example.net/uploads/attachments/ckhdsopzr0005rt9kn49eyzb5-double-rainbow.one-half.jpg" + one-third: + type: string + format: uri + example: "https://example.net/uploads/attachments/ckhdsopzr0005rt9kn49eyzb5-double-rainbow.one-third.jpg" + one-sixth: + type: string + format: uri + example: "https://example.net/uploads/attachments/ckhdsopzr0005rt9kn49eyzb5-double-rainbow.one-sixth.jpg" + original: + type: string + format: uri + example: "https://example.net/uploads/attachments/ckhdsopzr0005rt9kn49eyzb5-double-rainbow.jpg" + additionalProperties: + type: string + format: uri + _url: + type: string + format: uri + description: "Single URL for non-image files" + + # Relationship Field + RelationshipField: + type: array + description: "Array of related documents" + items: + type: object + properties: + _id: + type: string + example: "ckitdkktu002bu69krdkdu2pj" + archived: + type: boolean + disabled: + type: boolean + type: + type: string + description: "Document type" + example: "@apostrophecms/user" + title: + type: string + example: "Alexander Hamilton" + slug: + type: string + example: "user-alexander-hamilton" + metaType: + type: string + enum: [doc] + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + updatedBy: + type: object + properties: + _id: + type: string + firstName: + type: string + lastName: + type: string + username: + type: string + titleSortified: + type: string + highSearchText: + type: string + highSearchWords: + type: array + items: + type: string + lowSearchText: + type: string + searchSummary: + type: string + additionalProperties: true + + # Simple Field Types + BooleanField: + type: boolean + example: true + + StringField: + type: string + example: "String value" + + IntegerField: + type: integer + example: 42 + + FloatField: + type: number + format: float + example: 8675.309 + + DateField: + type: string + format: date + example: "2012-12-21" + + TimeField: + type: string + pattern: "^([0-1]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$" + example: "00:13:22" + + EmailField: + type: string + format: email + example: "jon@bonjovi.rocks" + + UrlField: + type: string + format: uri + example: "http://apostrophecms.com" + + SlugField: + type: string + pattern: "^[a-z0-9-]+$" + example: "slugified-string" + + ColorField: + type: string + pattern: "^#[0-9a-fA-F]{8}$" + example: "#9013feff" + + PasswordField: + type: string + description: "Password field - should not contain sensitive passwords in responses" + example: "don't use this for sensitive passwords" + + RangeField: + type: integer + description: "Numeric value within a specified range" + example: 21 + + SelectField: + type: string + description: "Selected value from predefined options" + example: "selected value" + + CheckboxesField: + type: array + description: "Array of selected checkbox values" + items: + type: string + example: ["med", "small"] + + # Common SEO Fields (often used together) + SEOFields: + type: object + description: "Common SEO metadata fields" + properties: + seoTitle: + $ref: '#/components/schemas/StringField' + seoDescription: + $ref: '#/components/schemas/StringField' + seoKeywords: + $ref: '#/components/schemas/StringField' + seoImage: + $ref: '#/components/schemas/AttachmentField' + additionalProperties: true + + User: + type: object + description: | + Built-in user piece type + Developers can add custom fields to the userl piece type in their project configuration. + properties: + _id: + type: string + description: Unique identifier + example: "clx1234567890abcdef" + title: + type: string + description: User's display name + example: "John Developer" + username: + type: string + description: Login username + example: "johndeveloper" + email: + type: string + format: email + description: User's email address + example: "john@example.com" + role: + type: string + description: User role + enum: ["guest", "contributor", "editor", "admin"] + example: "editor" + disabled: + type: boolean + description: Whether the user account is disabled + default: false + archived: + type: boolean + description: Whether the user is archived + default: false + visibility: + type: string + description: Visibility setting + enum: ["public", "loginRequired"] + default: "loginRequired" + type: + type: string + example: "@apostrophecms/user" + slug: + type: string + example: "user-johndeveloper" + createdAt: + type: string + format: date-time + description: Account creation date + updatedAt: + type: string + format: date-time + description: Last update date + + Global: + type: object + description: | + Built-in global content piece type for site-wide settings. + Developers can add custom fields to the global piece type in their project configuration. + properties: + _id: + type: string + description: Unique identifier + example: "global" + title: + type: string + description: Default title field (can be customized) + example: "My ApostropheCMS Site" + type: + type: string + example: "@apostrophecms/global" + # Example custom fields that might be added by developers: + # contactEmail: + # type: string + # format: email + # description: Site contact email (example custom field) + # footerContent: + # type: object + # description: Rich text area for footer (example custom field) + + Attachment: + type: object + description: File attachment information from upload endpoint + properties: + _id: + type: string + description: Unique attachment identifier + example: "ckj0akbxa003vp39kfbxgb8zg" + _url: + type: string + description: URL to the original file + example: "https://example.net/uploads/attachments/ckj0akbxa003vp39kfbxgb8zg-blue-box.png" + _urls: + type: object + description: URLs for different image sizes (images only) + additionalProperties: + type: string + name: + type: string + description: Slugified filename + example: "blue-box" + title: + type: string + description: Sortified filename + example: "blue box" + extension: + type: string + description: File extension + example: "png" + type: + type: string + example: "attachment" + group: + type: string + description: File group type + example: "images" + length: + type: integer + description: File size in bytes + example: 10497 + md5: + type: string + description: MD5 checksum + example: "630eeaaecd0bdc07c4a82eeca4c07588" + width: + type: integer + description: Image width in pixels (images only) + example: 600 + height: + type: integer + description: Image height in pixels (images only) + example: 106 + landscape: + type: boolean + description: Whether image is landscape orientation (images only) + portrait: + type: boolean + description: Whether image is portrait orientation (images only) + docIds: + type: array + items: + type: string + description: IDs of documents using this attachment + archivedDocIds: + type: array + items: + type: string + description: IDs of archived documents using this attachment + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + + Image: + type: object + description: Built-in image/media piece type + properties: + _id: + type: string + description: Unique identifier + example: "clx1234567890abcdef" + title: + type: string + description: Image title/alt text + example: "Hero banner image" + slug: + type: string + example: "hero-banner-image" + type: + type: string + example: "@apostrophecms/image" + archived: + type: boolean + default: false + visibility: + type: string + enum: ["public", "loginRequired"] + default: "public" + attachment: + type: object + description: File attachment information + properties: + _id: + type: string + name: + type: string + example: "hero-banner" + extension: + type: string + example: "jpg" + length: + type: integer + description: File size in bytes + url: + type: string + description: Public URL to access the image + example: "/uploads/attachments/clx123/hero-banner.jpg" + credit: + type: string + description: Image credit or attribution + tags: + type: array + items: + type: string + description: Image tags for organization + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + + File: + type: object + description: Built-in file piece type for general file uploads (PDFs, documents, etc.) + properties: + _id: + type: string + description: Unique identifier + example: "clx1234567890abcdef" + title: + type: string + description: File title/description + example: "Company Brochure" + slug: + type: string + example: "company-brochure" + type: + type: string + example: "@apostrophecms/file" + archived: + type: boolean + default: false + visibility: + type: string + enum: ["public", "loginRequired"] + default: "public" + attachment: + type: object + description: File attachment information + properties: + _id: + type: string + name: + type: string + example: "company-brochure" + extension: + type: string + example: "pdf" + length: + type: integer + description: File size in bytes + url: + type: string + description: Public URL to access the file + example: "/uploads/attachments/clx123/company-brochure.pdf" + description: + type: string + description: File description + tags: + type: array + items: + type: string + description: File tags for organization + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + + ImageTag: + type: object + description: Built-in image tag piece type for organizing images + properties: + _id: + type: string + example: "clx1234567890abcdef" + title: + type: string + description: Tag name + example: "Hero Images" + slug: + type: string + description: URL-friendly tag name + example: "hero-images" + type: + type: string + example: "@apostrophecms/image-tag" + archived: + type: boolean + default: false + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + + FileTag: + type: object + description: Built-in file tag piece type for organizing files + properties: + _id: + type: string + example: "clx1234567890abcdef" + title: + type: string + description: Tag name + example: "Marketing Materials" + slug: + type: string + description: URL-friendly tag name + example: "marketing-materials" + type: + type: string + example: "@apostrophecms/file-tag" + archived: + type: boolean + default: false + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + + Article: + type: object + description: Example custom piece type - blog article (requires custom configuration) + properties: + _id: + type: string + description: Unique identifier + example: "clx1234567890abcdef" + title: + type: string + description: Article title + example: "Getting Started with Headless CMS" + slug: + type: string + description: URL-friendly version of title + example: "getting-started-headless-cms" + type: + type: string + example: "article" + archived: + type: boolean + default: false + visibility: + type: string + enum: ["public", "loginRequired"] + default: "public" + body: + type: object + description: Rich text content area + properties: + metaType: + type: string + example: "area" + items: + type: array + items: + type: object + description: Content widgets (rich text, images, etc.) + publishedAt: + type: string + format: date-time + description: Publication date + example: "2024-12-15T10:30:00.000Z" + tags: + type: array + items: + type: string + description: Article tags + example: ["cms", "headless", "tutorial"] + _author: + type: array + items: + $ref: '#/components/schemas/User' + description: Article authors (relationship field) + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + + Event: + type: object + description: Example custom piece type - calendar event (requires custom configuration) + properties: + _id: + type: string + example: "clx1234567890abcdef" + title: + type: string + example: "ApostropheCMS Meetup" + slug: + type: string + example: "apostrophecms-meetup" + type: + type: string + example: "event" + archived: + type: boolean + default: false + visibility: + type: string + enum: ["public", "loginRequired"] + default: "public" + description: + type: object + description: Rich text event description + startDate: + type: string + format: date-time + example: "2024-12-20T18:00:00.000Z" + endDate: + type: string + format: date-time + example: "2024-12-20T20:00:00.000Z" + location: + type: string + example: "123 Developer Street, Tech City" + _image: + type: array + items: + $ref: '#/components/schemas/Image' + description: Event images (relationship field) + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + + # Generic piece response structure + PieceResponse: + type: object + properties: + success: + type: boolean + description: Whether the request was successful + data: + type: object + description: The piece data + error: + type: string + description: Error message if success is false + + # API Response schemas + PaginatedResponse: + type: object + properties: + success: + type: boolean + data: + type: object + properties: + results: + type: array + items: + type: object + description: Array of pieces (type depends on endpoint) + pages: + type: integer + description: Total number of pages + currentPage: + type: integer + description: Current page number (1-based) + total: + type: integer + description: Total number of items across all pages + + CreatePieceRequest: + type: object + description: Generic structure for creating any piece type + required: + - title + properties: + title: + type: string + description: Piece title (required for all piece types) + slug: + type: string + description: URL slug (auto-generated from title if not provided) + visibility: + type: string + enum: ["public", "loginRequired"] + description: Visibility setting + default: "public" + archived: + type: boolean + description: Whether the piece is archived + default: false + + Error: + type: object + properties: + error: + type: string + description: Error message + message: + type: string + description: Detailed error message + + LocalesResponse: + type: object + description: "Object containing all configured locales" + additionalProperties: + type: object + properties: + label: + type: string + description: "Human-readable locale name" + example: "English" + _edit: + type: boolean + description: "Whether current user can edit content in this locale" + example: true + example: + en: + label: "English" + _edit: true + fr: + label: "French" + _edit: false + + # i18n Request Schemas + LocaleRequest: + type: object + required: + - locale + properties: + locale: + type: string + description: "Target locale code" + example: "fr" + contextDocId: + type: string + description: "Optional document ID for the path" + example: "cloydg3ka0005qcls5vmg8sb9" + clipboard: + type: string + description: "Optional clipboard content for cross-domain situations" + example: "exampleClipboardContent" + + SameHostnameResponse: + type: object + properties: + redirectTo: + type: string + description: "Path to redirect to within same hostname" + example: "/fr/page-slug" + + DifferentHostnameResponse: + type: object + properties: + redirectTo: + type: string + format: uri + description: "Full URL to redirect to with cross-domain session token" + example: "https://fr.example.com/french-example-page?aposCrossDomainSessionToken=generated_token" + + ExistInLocaleRequest: + type: object + required: + - ids + - locale + - mode + properties: + ids: + type: array + items: + type: string + description: "Array of document IDs to check" + example: ["cloydg3ka0005qcls5vmg8sb9", "cloydg3ka0005qcls5vmg8sb8"] + locale: + type: string + description: "Locale to check documents in" + example: "fr" + mode: + type: string + enum: [draft, published] + description: "Mode to check documents in" + example: "published" + + ExistInLocaleResponse: + type: object + properties: + originalLocaleIds: + type: array + items: + type: string + description: "Array of document IDs in the original locale and mode" + example: ["cloydg3ka0005qcls5vmg8sb9:en:published", "cloydg3ka0005qcls5vmg8sb8:en:published"] + newLocaleIds: + type: array + items: + type: string + description: "Array of document IDs in the new locale" + example: ["cloydg3ka0005qcls5vmg8sb9:fr:published", "cloydg3ka0005qcls5vmg8sb8:fr:published"] + aposDocIds: + type: array + items: + type: string + description: "Array of aposDocId values for the documents" + example: ["cloydg3ka0005qcls5vmg8sb9", "cloydg3ka0005qcls5vmg8sb8"] + + responses: + BadRequest: + description: Bad request - invalid input parameters + content: + application/json: + schema: + type: object + properties: + error: + type: string + example: "Invalid request parameters" + message: + type: string + example: "The request could not be processed due to invalid input" + + Unauthorized: + description: Authentication required + content: + application/json: + schema: + type: object + properties: + error: + type: string + example: "Unauthorized" + message: + type: string + example: "Authentication is required to access this resource" + + Forbidden: + description: Access forbidden - insufficient permissions + content: + application/json: + schema: + type: object + properties: + error: + type: string + example: "Forbidden" + message: + type: string + example: "You do not have permission to perform this action" + + NotFound: + description: Resource not found + content: + application/json: + schema: + type: object + properties: + error: + type: string + example: "Not Found" + message: + type: string + example: "The requested resource could not be found" + +paths: + # Authentication endpoints + /@apostrophecms/login/login: + post: + summary: Login to get bearer token or session cookie + description: | + Authenticate and receive either a bearer token or session cookie for subsequent API requests. + + - For bearer token: omit `session` field or set to `false` + - For session cookie: set `session` to `true` and include `credentials: 'include'` in fetch + tags: + - Authentication + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - username + - password + properties: + username: + type: string + description: User's login username + example: "admin" + password: + type: string + format: password + description: User's password + session: + type: boolean + description: Set to true to receive session cookie instead of bearer token + default: false + example: false + examples: + bearer_token: + summary: Request bearer token + value: + username: "admin" + password: "your-password" + session_cookie: + summary: Request session cookie + value: + username: "admin" + password: "your-password" + session: true + responses: + '200': + description: Login successful + content: + application/json: + schema: + type: object + properties: + token: + type: string + description: Bearer token (only present when session is false/omitted) + example: "random123Token456xyz" + examples: + bearer_response: + summary: Bearer token response + value: + token: "random123Token456xyz" + session_response: + summary: Session cookie response (token field not present) + value: {} + headers: + Set-Cookie: + description: Session cookie (only when session=true) + schema: + type: string + example: "apostrophe.sid=s%3A...; Path=/; HttpOnly" + '401': + description: Invalid credentials + content: + application/json: + schema: + type: object + properties: + error: + type: string + example: "Invalid credentials" + '400': + description: Bad request - missing required fields + + /@apostrophecms/login/logout: + post: + summary: Logout and invalidate token/session + description: | + End the current session or invalidate the bearer token. + + - For bearer token: include Authorization header + - For session cookie: include credentials in request + tags: + - Authentication + responses: + '200': + description: Logout successful + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + example: true + '401': + description: Not authenticated + security: + - BearerAuth: [] + - SessionAuth: [] + + # Page endpoints + /@apostrophecms/page: + get: + tags: + - Pages + summary: Get page tree + description: | + Fetch the home page and all other pages structured in the home page's `_children` property. + Returns the complete page hierarchy starting from the home page. + parameters: + - $ref: '#/components/parameters/AllPages' + - $ref: '#/components/parameters/FlatResponse' + - $ref: '#/components/parameters/ChildrenParam' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + responses: + '200': + description: Page tree retrieved successfully + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PageTreeResponse' + - $ref: '#/components/schemas/FlatPageResponse' + examples: + tree_response: + summary: Tree structure response + value: + _id: "ckhdscx5900054z9k88uqs16w" + title: "Home Page" + slug: "/" + type: "@apostrophecms/home-page" + _children: [] + flat_response: + summary: Flat array response + value: + results: [] + '400': + description: Bad request - Invalid image ID format + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Page not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + - {} # Allows unauthenticated access if publicApiProjection is defined + + post: + tags: + - Pages + summary: Create new page + description: | + Insert a new page at the specified position in the page tree. + Requires `_targetId` and `_position` to determine placement. + parameters: + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PageCreateRequest' + examples: + new_page: + summary: Create new page as first child + value: + title: "New Page" + _targetId: "ckhdscx5900054z9k88uqs16w" + _position: "firstChild" + copy_page: + summary: Create page by copying existing one + value: + title: "Copied Page" + _targetId: "_home" + _position: "lastChild" + _copyingId: "existing-page-id" + responses: + '201': + description: Page created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/PageTreeResponse' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/page/{_id}: + get: + tags: + - Pages + summary: Get single page + description: | + Fetch a single page document by ID. The ID can include mode and locale + (e.g., `id:en:published`) or use query parameters to specify them. + parameters: + - $ref: '#/components/parameters/PageId' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/RenderAreas' + responses: + '200': + description: Page retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/PageTreeResponse' + '400': + description: Bad request - Invalid image ID format + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Page with that ID doesn't exist + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + - {} # Allows unauthenticated access if publicApiProjection is defined + + put: + tags: + - Pages + summary: Replace page + description: | + Completely replace a page document. Requires `_targetId` and `_position` + for page tree positioning. + parameters: + - $ref: '#/components/parameters/PageId' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/RenderAreas' + requestBody: + required: true + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/PageCreateRequest' + - type: object + required: + - _targetId + - _position + responses: + '200': + description: Page replaced successfully + content: + application/json: + schema: + $ref: '#/components/schemas/PageTreeResponse' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + patch: + tags: + - Pages + summary: Update page + description: | + Partially update a page document. Can use MongoDB-style operators + and dot notation for nested properties. Include `_targetId` and `_position` + to move the page within the tree. + parameters: + - $ref: '#/components/parameters/PageId' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PageUpdateRequest' + examples: + update_title: + summary: Update page title only + value: + title: "Updated Page Title" + move_page: + summary: Move page to new position + value: + _targetId: "target-page-id" + _position: "after" + archive_page: + summary: Move page to archive + value: + _targetId: "_archive" + _position: "lastChild" + dot_notation: + summary: Update nested content with dot notation + value: + "description.items.0.content": "

Updated content

" + responses: + '200': + description: Page updated successfully + content: + application/json: + schema: + $ref: '#/components/schemas/PageTreeResponse' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + delete: + tags: + - Pages + summary: Delete page + description: | + **Permanently delete a page document.** This cannot be undone. + + Restrictions: + - Cannot delete home page + - Cannot delete pages with children (delete children first) + - Cannot delete draft if published version exists + parameters: + - $ref: '#/components/parameters/PageId' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + responses: + '200': + description: Page deleted successfully + '400': + description: Deletion not allowed + content: + application/json: + schema: + type: object + properties: + name: + type: string + example: "invalid" + data: + type: object + message: + type: string + example: "You must delete the children of this page first." + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/page/{_id}/publish: + post: + tags: + - Pages + summary: Publish page draft + description: | + Publish an existing draft mode document. The `_id` can be from either + the draft or published version, or use the `aposDocId`. + parameters: + - $ref: '#/components/parameters/PageId' + - $ref: '#/components/parameters/AposLocale' + responses: + '200': + description: Page published successfully + content: + application/json: + schema: + $ref: '#/components/schemas/PageTreeResponse' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /{_url}: + get: + tags: + - Pages + summary: Get rendered page content + description: | + Get a page's rendered HTML content. With `aposRefresh=1`, returns only + the refreshable content without the full page layout (used by Apostrophe UI). + parameters: + - name: _url + in: path + required: true + description: Page URL path + schema: + type: string + example: "/about-us" + - name: aposRefresh + in: query + description: Return only refreshable content without full layout + schema: + type: string + enum: ["1"] + example: "1" + responses: + '200': + description: Page content retrieved successfully + content: + text/html: + schema: + type: string + description: Rendered HTML content + '404': + $ref: '#/components/responses/NotFound' + + # Built-in piece types + /@apostrophecms/user: + get: + summary: Get users + description: Retrieve users (requires admin permissions) + tags: + - Users (Built-in) + parameters: + - $ref: '#/components/parameters/Page' + - $ref: '#/components/parameters/PerPage' + - $ref: '#/components/parameters/Search' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/RenderAreas' + responses: + '200': + description: Successful response + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/PaginatedResponse' + - type: object + properties: + results: + type: array + items: + $ref: '#/components/schemas/User' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - admin required + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + - {} # Allows unauthenticated IF publicApiProjection is defined + + post: + summary: Create user + description: Create a new user account (requires admin permissions) + tags: + - Users (Built-in) + parameters: + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - title + - username + - email + - password + properties: + title: + type: string + example: "Jane Developer" + username: + type: string + example: "janedeveloper" + email: + type: string + format: email + example: "jane@example.com" + password: + type: string + format: password + description: User password + role: + type: string + enum: ["guest", "contributor", "editor", "admin"] + default: "contributor" + disabled: + type: boolean + default: false + responses: + '201': + description: User created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + description: Bad request - validation errors + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - admin required + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/user/{id}: + get: + summary: Get single user + description: Retrieve a specific user by ID (requires appropriate permissions) + tags: + - Users (Built-in) + parameters: + - name: id + in: path + required: true + description: User ID + schema: + type: string + example: "clx1234567890abcdef" + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/RenderAreas' + responses: + '200': + description: User retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + description: Bad request - Invalid user ID format + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - Insufficient permissions to view this user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: User not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + put: + summary: Replace user + description: Completely replace a user document + tags: + - Users (Built-in) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - title + - username + - email + properties: + title: + type: string + username: + type: string + email: + type: string + format: email + role: + type: string + enum: ["guest", "contributor", "editor", "admin"] + disabled: + type: boolean + responses: + '200': + description: User updated + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: User not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + patch: + summary: Update user fields + description: Update specific fields of a user + tags: + - Users (Built-in) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + title: + type: string + email: + type: string + format: email + role: + type: string + enum: ["guest", "contributor", "editor", "admin"] + disabled: + type: boolean + description: Only include fields to update + responses: + '200': + description: User updated + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: User not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + delete: + summary: Delete user + description: Permanently delete a user + tags: + - Users (Built-in) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + responses: + '200': + description: User deleted + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: User not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/user/{id}/publish: + post: + summary: Publish user draft + description: Publish the draft version of a user + tags: + - Users (Built-in) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposLocale' + responses: + '200': + description: User published + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: User not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/global: + get: + summary: Get global content + description: Retrieve site-wide global content and settings + tags: + - Global Content (Built-in) + parameters: + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/RenderAreas' + responses: + '200': + description: Global content retrieved + content: + application/json: + schema: + $ref: '#/components/schemas/Global' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + - {} # Allows unauthenticated IF publicApiProjection is defined + + put: + summary: Update global content + description: Update site-wide global content (requires editor permissions) + tags: + - Global Content (Built-in) + parameters: + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + title: + type: string + description: Site title + # Custom fields would be defined in project configuration + description: Fields depend on project configuration + responses: + '200': + description: Global content updated + content: + application/json: + schema: + $ref: '#/components/schemas/Global' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - editor required + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + patch: + summary: Partially update global content + description: Update specific fields in global content without affecting others (requires editor permissions) + tags: + - Global Content (Built-in) + parameters: + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + title: + type: string + description: Site title + # Custom fields would be defined in project configuration + description: Only include fields you want to update - other fields remain unchanged + additionalProperties: true + responses: + '200': + description: Global content partially updated + content: + application/json: + schema: + $ref: '#/components/schemas/Global' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - editor required + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/image: + get: + summary: Get images + description: | + Retrieve images from the media library. + Authentication is required for all requests other than GET requests + for images with defined publicApiProjection. + tags: + - Media (Built-in) + parameters: + - $ref: '#/components/parameters/Page' + - $ref: '#/components/parameters/PerPage' + - $ref: '#/components/parameters/Search' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/RenderAreas' + responses: + '200': + description: Images retrieved successfully + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/PaginatedResponse' + - type: object + properties: + results: + type: array + items: + $ref: '#/components/schemas/Image' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + - {} # Allows unauthenticated access if publicApiProjection is defined + + post: + summary: Create image + description: Create a new image document (requires prior attachment upload) + tags: + - Media (Built-in) + parameters: + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - title + - attachment + properties: + title: + type: string + example: "Beautiful Landscape" + attachment: + $ref: '#/components/schemas/Attachment' + description: Attachment object from upload endpoint + alt: + type: string + description: Alt text for accessibility + example: "A beautiful mountain landscape at sunset" + credit: + type: string + description: Photo credit + example: "Photo by John Doe" + responses: + '201': + description: Image created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Image' + '400': + description: Bad request - validation errors + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/image/{id}: + get: + summary: Get single image + description: | + Retrieve a specific image by ID from the media library. + Authentication is required for all requests other than GET requests + for images with defined publicApiProjection. + tags: + - Media (Built-in) + parameters: + - name: id + in: path + required: true + description: Image ID + schema: + type: string + example: "clx1234567890abcdef" + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/RenderAreas' + responses: + '200': + description: Image retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Image' + '400': + description: Bad request - Invalid image ID format + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Image not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + - {} # Allows unauthenticated access if publicApiProjection is defined + + put: + summary: Replace image + description: Completely replace an image document + tags: + - Media (Built-in) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - title + - attachment + properties: + title: + type: string + attachment: + $ref: '#/components/schemas/Attachment' + alt: + type: string + credit: + type: string + responses: + '200': + description: Image updated + content: + application/json: + schema: + $ref: '#/components/schemas/Image' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Image not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + patch: + summary: Update image fields + description: Update specific fields of an image + tags: + - Media (Built-in) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + title: + type: string + alt: + type: string + credit: + type: string + description: Only include fields to update + responses: + '200': + description: Image updated + content: + application/json: + schema: + $ref: '#/components/schemas/Image' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Image not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + delete: + summary: Delete image + description: Permanently delete an image + tags: + - Media (Built-in) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + responses: + '200': + description: Image deleted + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Image not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/image/{id}/publish: + post: + summary: Publish image draft + description: Publish the draft version of an image + tags: + - Media (Built-in) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposLocale' + responses: + '200': + description: Image published + content: + application/json: + schema: + $ref: '#/components/schemas/Image' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Image not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/file: + get: + summary: Get files + description: | + Retrieve files from the media library. + Authentication is required for all requests other than GET requests + for files with defined publicApiProjection. + tags: + - Media (Built-in) + parameters: + - $ref: '#/components/parameters/Page' + - $ref: '#/components/parameters/PerPage' + - $ref: '#/components/parameters/Search' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/RenderAreas' + responses: + '200': + description: Files retrieved successfully + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/PaginatedResponse' + - type: object + properties: + results: + type: array + items: + $ref: '#/components/schemas/File' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + - {} # Allows unauthenticated access if publicApiProjection is defined + + post: + summary: Create file + description: Create a new file document (requires prior attachment upload) + tags: + - Media (Built-in) + parameters: + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - title + - attachment + properties: + title: + type: string + example: "Important Document" + attachment: + $ref: '#/components/schemas/Attachment' + description: Attachment object from upload endpoint + description: + type: string + description: File description + example: "Quarterly report PDF" + responses: + '201': + description: File created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/File' + '400': + description: Bad request - validation errors + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/file/{id}: + get: + summary: Get single file + description: | + Retrieve a specific file by ID from the media library. + Authentication is required for all requests other than GET requests + for files with defined publicApiProjection. + tags: + - Media (Built-in) + parameters: + - name: id + in: path + required: true + description: File ID + schema: + type: string + example: "clx1234567890abcdef" + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/RenderAreas' + responses: + '200': + description: File retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/File' + '400': + description: Bad request - Invalid file ID format + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: File not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + - {} # Allows unauthenticated access if publicApiProjection is defined + + put: + summary: Replace file + description: Completely replace a file document + tags: + - Media (Built-in) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - title + - attachment + properties: + title: + type: string + attachment: + $ref: '#/components/schemas/Attachment' + description: + type: string + responses: + '200': + description: File updated + content: + application/json: + schema: + $ref: '#/components/schemas/File' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: File not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + patch: + summary: Update file fields + description: Update specific fields of a file + tags: + - Media (Built-in) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + title: + type: string + description: + type: string + description: Only include fields to update + responses: + '200': + description: File updated + content: + application/json: + schema: + $ref: '#/components/schemas/File' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: File not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + delete: + summary: Delete file + description: Permanently delete a file + tags: + - Media (Built-in) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + responses: + '200': + description: File deleted + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: File not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/file/{id}/publish: + post: + summary: Publish file draft + description: Publish the draft version of a file + tags: + - Media (Built-in) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposLocale' + responses: + '200': + description: File published + content: + application/json: + schema: + $ref: '#/components/schemas/File' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: File not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/image-tag: + get: + summary: Get image tags + description: Retrieve image tags for organizing images + tags: + - Media (Built-in) + parameters: + - $ref: '#/components/parameters/Page' + - $ref: '#/components/parameters/PerPage' + - $ref: '#/components/parameters/Search' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/RenderAreas' + responses: + '200': + description: Successful response + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/PaginatedResponse' + - type: object + properties: + results: + type: array + items: + $ref: '#/components/schemas/ImageTag' + '400': + description: Bad request - Invalid file ID format + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: File not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + - {} # Allows unauthenticated access if publicApiProjection is defined + + post: + summary: Create image tag + description: Create a new image tag for organizing images + tags: + - Media (Built-in) + parameters: + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - title + properties: + title: + type: string + example: "Hero Images" + description: Tag name + slug: + type: string + example: "hero-images" + description: URL-friendly identifier (auto-generated if not provided) + responses: + '201': + description: Image tag created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/ImageTag' + '400': + description: Bad request - validation errors + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/image-tag/{id}: + get: + summary: Get single image tag + description: Retrieve a specific image tag by ID + tags: + - Media (Built-in) + parameters: + - name: id + in: path + required: true + description: Image tag ID + schema: + type: string + example: "clx1234567890abcdef" + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/RenderAreas' + responses: + '200': + description: Image tag found + content: + application/json: + schema: + $ref: '#/components/schemas/ImageTag' + '400': + description: Bad request - Invalid file ID format + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: File not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + put: + summary: Replace image tag + description: Completely replace an image tag document + tags: + - Media (Built-in) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - title + properties: + title: + type: string + slug: + type: string + responses: + '200': + description: Image tag updated + content: + application/json: + schema: + $ref: '#/components/schemas/ImageTag' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Image tag not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + patch: + summary: Update image tag fields + description: Update specific fields of an image tag + tags: + - Media (Built-in) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + title: + type: string + slug: + type: string + description: Only include fields to update + responses: + '200': + description: Image tag updated + content: + application/json: + schema: + $ref: '#/components/schemas/ImageTag' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Image tag not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + delete: + summary: Delete image tag + description: Permanently delete an image tag + tags: + - Media (Built-in) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + responses: + '200': + description: Image tag deleted + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Image tag not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/image-tag/{id}/publish: + post: + summary: Publish image tag draft + description: Publish the draft version of an image tag + tags: + - Media (Built-in) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposLocale' + responses: + '200': + description: Image tag published + content: + application/json: + schema: + $ref: '#/components/schemas/ImageTag' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Image tag not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/file-tag: + get: + summary: Get file tags + description: Retrieve file tags for organizing files + tags: + - Media (Built-in) + parameters: + - $ref: '#/components/parameters/Page' + - $ref: '#/components/parameters/PerPage' + - $ref: '#/components/parameters/Search' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/RenderAreas' + responses: + '200': + description: Successful response + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/PaginatedResponse' + - type: object + properties: + results: + type: array + items: + $ref: '#/components/schemas/FileTag' + '400': + description: Bad request - Invalid file ID format + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: File not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + - {} # Allows unauthenticated access if publicApiProjection is defined + + post: + summary: Create file tag + description: Create a new file tag for organizing files + tags: + - Media (Built-in) + parameters: + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - title + properties: + title: + type: string + example: "Marketing Materials" + description: Tag name + slug: + type: string + example: "marketing-materials" + description: URL-friendly identifier (auto-generated if not provided) + responses: + '201': + description: File tag created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/FileTag' + '400': + description: Bad request - validation errors + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/file-tag/{id}: + get: + summary: Get single file tag + description: Retrieve a specific file tag by ID + tags: + - Media (Built-in) + parameters: + - name: id + in: path + required: true + description: File tag ID + schema: + type: string + example: "clx1234567890abcdef" + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/RenderAreas' + responses: + '200': + description: File tag found + content: + application/json: + schema: + $ref: '#/components/schemas/FileTag' + '400': + description: Bad request - Invalid file ID format + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: File not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + - {} # Allows unauthenticated access if publicApiProjection is defined + + put: + summary: Replace file tag + description: Completely replace a file tag document + tags: + - Media (Built-in) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - title + properties: + title: + type: string + slug: + type: string + responses: + '200': + description: File tag updated + content: + application/json: + schema: + $ref: '#/components/schemas/FileTag' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: File tag not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + patch: + summary: Update file tag fields + description: Update specific fields of a file tag + tags: + - Media (Built-in) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + title: + type: string + slug: + type: string + description: Only include fields to update + responses: + '200': + description: File tag updated + content: + application/json: + schema: + $ref: '#/components/schemas/FileTag' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: File tag not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + delete: + summary: Delete file tag + description: Permanently delete a file tag + tags: + - Media (Built-in) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + responses: + '200': + description: File tag deleted + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: File tag not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/file-tag/{id}/publish: + post: + summary: Publish file tag draft + description: Publish the draft version of a file tag + tags: + - Media (Built-in) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposLocale' + responses: + '200': + description: File tag published + content: + application/json: + schema: + $ref: '#/components/schemas/FileTag' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: File tag not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/attachment/upload: + post: + summary: Upload media file + description: | + Upload a media file to create an attachment. The uploaded file can then be used + to create image or file documents. Uses multipart/form-data encoding with the + file uploaded under the name 'file'. + tags: + - Attachments (Built-in) + parameters: + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + required: + - file + properties: + file: + type: string + format: binary + description: The file to upload + encoding: + file: + contentType: image/*, application/pdf, application/*, text/* + responses: + '200': + description: File uploaded successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Attachment' + '400': + description: Bad request - invalid file or missing file + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized - authentication required + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '413': + description: File too large + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '415': + description: Unsupported file type + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/attachment/crop: + post: + summary: Crop image attachment + description: | + Create a cropped version of an existing image attachment. The crop object + is appended to the crops array property of the attachment document. + The newly uploaded image file will be stored with a filename using the + crop properties: {_id}-{name}.{top}.{left}.{width}.{height}.{extension} + tags: + - Attachments (Built-in) + parameters: + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - _id + - crop + properties: + _id: + type: string + description: The _id property of an existing image attachment document + example: "ckj0akbxa003vp39kfbxgb8zg" + crop: + type: object + description: Crop coordinates and dimensions + required: + - top + - left + - width + - height + properties: + top: + type: integer + description: Top coordinate of the crop area (pixels) + example: 10 + minimum: 0 + left: + type: integer + description: Left coordinate of the crop area (pixels) + example: 15 + minimum: 0 + width: + type: integer + description: Width of the crop area (pixels) + example: 300 + minimum: 1 + height: + type: integer + description: Height of the crop area (pixels) + example: 200 + minimum: 1 + responses: + '200': + description: Image cropped successfully + content: + application/json: + schema: + type: boolean + example: true + description: Returns true on successful crop + '400': + description: Bad request - invalid attachment ID or crop parameters + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized - authentication required + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Attachment not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '422': + description: Unprocessable entity - crop coordinates exceed image bounds + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /article: + get: + summary: Get articles + description: Retrieve blog articles (custom piece type) + tags: + - Articles (Custom) + parameters: + - $ref: '#/components/parameters/Page' + - $ref: '#/components/parameters/PerPage' + - $ref: '#/components/parameters/Search' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/RenderAreas' + # Custom query parameters for articles + - name: tags + in: query + description: Filter by article tags + schema: + type: array + items: + type: string + style: form + explode: true + example: ["cms", "tutorial"] + - name: _author + in: query + description: Filter by author ID + schema: + type: string + example: "clx1234567890abcdef" + - name: author + in: query + description: Filter by author slug + schema: + type: string + example: "john-doe" + - name: publishedAt + in: query + description: Filter by publication date + schema: + type: string + format: date + example: "2024-12-15" + responses: + '200': + description: Successful response + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/PaginatedResponse' + - type: object + properties: + results: + type: array + items: + $ref: '#/components/schemas/Article' + '400': + description: Bad request - Invalid file ID format + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: File not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + - {} # Allows unauthenticated access if publicApiProjection is defined + + post: + summary: Create article + description: Create a new blog article + tags: + - Articles (Custom) + parameters: + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - title + properties: + title: + type: string + example: "Getting Started with Headless CMS" + slug: + type: string + example: "getting-started-headless-cms" + description: Auto-generated from title if not provided + body: + type: object + description: Rich text content area + properties: + metaType: + type: string + example: "area" + items: + type: array + items: + type: object + description: Content widgets (rich text, images, etc.) + publishedAt: + type: string + format: date-time + description: Publication date + example: "2024-12-15T10:30:00.000Z" + tags: + type: array + items: + type: string + description: Article tags + example: ["cms", "headless", "tutorial"] + _author: + type: array + items: + type: string + description: Author IDs (relationship field) + example: ["clx1234567890abcdef"] + visibility: + type: string + enum: ["public", "loginRequired"] + default: "public" + responses: + '201': + description: Article created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Article' + '400': + description: Bad request - validation errors + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /article/{id}: + get: + summary: Get single article + description: Retrieve a specific article by ID + tags: + - Articles (Custom) + parameters: + - name: id + in: path + required: true + description: Article ID + schema: + type: string + example: "clx1234567890abcdef" + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/RenderAreas' + responses: + '200': + description: Article found + content: + application/json: + schema: + $ref: '#/components/schemas/Article' + '400': + description: Bad request - Invalid file ID format + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: File not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + put: + summary: Replace article + description: Completely replace an article document + tags: + - Articles (Custom) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - title + properties: + title: + type: string + slug: + type: string + body: + type: object + publishedAt: + type: string + format: date-time + tags: + type: array + items: + type: string + _author: + type: array + items: + type: string + visibility: + type: string + enum: ["public", "loginRequired"] + responses: + '200': + description: Article updated + content: + application/json: + schema: + $ref: '#/components/schemas/Article' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Article not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + patch: + summary: Update article fields + description: Update specific fields of an article + tags: + - Articles (Custom) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + title: + type: string + slug: + type: string + body: + type: object + publishedAt: + type: string + format: date-time + tags: + type: array + items: + type: string + _author: + type: array + items: + type: string + visibility: + type: string + enum: ["public", "loginRequired"] + description: Only include fields to update + responses: + '200': + description: Article updated + content: + application/json: + schema: + $ref: '#/components/schemas/Article' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Article not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + delete: + summary: Delete article + description: Permanently delete an article + tags: + - Articles (Custom) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + responses: + '200': + description: Article deleted + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Article not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /article/{id}/publish: + post: + summary: Publish article draft + description: Publish the draft version of an article + tags: + - Articles (Custom) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposLocale' + responses: + '200': + description: Article published + content: + application/json: + schema: + $ref: '#/components/schemas/Article' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Article not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /event: + get: + summary: Get events + description: Retrieve calendar events (custom piece type) + tags: + - Events (Custom) + parameters: + - $ref: '#/components/parameters/Page' + - $ref: '#/components/parameters/PerPage' + - $ref: '#/components/parameters/Search' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/RenderAreas' + # Custom query parameters for events + - name: startDate + in: query + description: Filter events by start date (exact match) + schema: + type: string + format: date + example: "2024-12-20" + - name: startDateFrom + in: query + description: Filter events starting from this date + schema: + type: string + format: date + example: "2024-12-01" + - name: startDateTo + in: query + description: Filter events starting before this date + schema: + type: string + format: date + example: "2024-12-31" + - name: location + in: query + description: Filter by event location + schema: + type: string + example: "Tech City" + - name: _image + in: query + description: Filter by image ID + schema: + type: string + example: "clx1234567890abcdef" + responses: + '200': + description: Successful response + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/PaginatedResponse' + - type: object + properties: + results: + type: array + items: + $ref: '#/components/schemas/Event' + '400': + description: Bad request - Invalid file ID format + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: File not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + - {} # Allows unauthenticated access if publicApiProjection is defined + + post: + summary: Create event + description: Create a new calendar event + tags: + - Events (Custom) + parameters: + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - title + - startDate + properties: + title: + type: string + example: "ApostropheCMS Meetup" + slug: + type: string + example: "apostrophecms-meetup" + description: Auto-generated from title if not provided + description: + type: object + description: Rich text event description + startDate: + type: string + format: date-time + example: "2024-12-20T18:00:00.000Z" + endDate: + type: string + format: date-time + example: "2024-12-20T20:00:00.000Z" + location: + type: string + example: "123 Developer Street, Tech City" + _image: + type: array + items: + type: string + description: Event image IDs (relationship field) + example: ["clx1234567890abcdef"] + visibility: + type: string + enum: ["public", "loginRequired"] + default: "public" + responses: + '201': + description: Event created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Event' + '400': + description: Bad request - validation errors + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /event/{id}: + get: + summary: Get single event + description: Retrieve a specific event by ID + tags: + - Events (Custom) + parameters: + - name: id + in: path + required: true + description: Event ID + schema: + type: string + example: "clx1234567890abcdef" + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/RenderAreas' + responses: + '200': + description: Event found + content: + application/json: + schema: + $ref: '#/components/schemas/Event' + '404': + description: Event not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + put: + summary: Replace event + description: Completely replace an event document + tags: + - Events (Custom) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - title + - startDate + properties: + title: + type: string + slug: + type: string + description: + type: object + startDate: + type: string + format: date-time + endDate: + type: string + format: date-time + location: + type: string + _image: + type: array + items: + type: string + visibility: + type: string + enum: ["public", "loginRequired"] + responses: + '200': + description: Event updated + content: + application/json: + schema: + $ref: '#/components/schemas/Event' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Event not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + patch: + summary: Update event fields + description: Update specific fields of an event + tags: + - Events (Custom) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + title: + type: string + slug: + type: string + description: + type: object + startDate: + type: string + format: date-time + endDate: + type: string + format: date-time + location: + type: string + _image: + type: array + items: + type: string + visibility: + type: string + enum: ["public", "loginRequired"] + description: Only include fields to update + responses: + '200': + description: Event updated + content: + application/json: + schema: + $ref: '#/components/schemas/Event' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Event not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + delete: + summary: Delete event + description: Permanently delete an event + tags: + - Events (Custom) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + responses: + '200': + description: Event deleted + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Event not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /event/{id}/publish: + post: + summary: Publish event draft + description: Publish the draft version of an event + tags: + - Events (Custom) + parameters: + - name: id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/AposLocale' + responses: + '200': + description: Event published + content: + application/json: + schema: + $ref: '#/components/schemas/Event' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Event not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/i18n/locales: + get: + tags: + - Internationalization + summary: Get all configured locales + description: | + Returns information about all configured locales including labels and edit permissions. + Authentication is required to access locale configuration data. + responses: + '200': + description: Locales retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/LocalesResponse' + example: + en: + label: "English" + _edit: true + fr: + label: "French" + _edit: false + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/i18n/locale: + post: + tags: + - Internationalization + summary: Get locale path and manage clipboard + description: | + Returns the path to a locale home-page or optional document and makes the clipboard + available in the given locale. Used for cross-locale navigation. + parameters: + - name: contextDocId + in: query + description: Optional document ID for the path, defaults to locale home-page + required: false + schema: + type: string + example: "cloydg3ka0005qcls5vmg8sb9" + - name: locale + in: query + description: Required. The locale for the desired path + required: true + schema: + type: string + example: "fr" + - name: clipboard + in: query + description: Optional clipboard content for cross-domain situations + required: false + schema: + type: string + example: "exampleClipboardContent" + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/LocaleRequest' + examples: + basic_locale_switch: + summary: Basic locale switch to home page + value: + locale: "fr" + with_context_doc: + summary: Switch locale for specific document + value: + locale: "fr" + contextDocId: "cloydg3ka0005qcls5vmg8sb9" + with_clipboard: + summary: Cross-domain switch with clipboard + value: + locale: "fr" + contextDocId: "cloydg3ka0005qcls5vmg8sb9" + clipboard: "exampleClipboardContent" + responses: + '200': + description: Locale path retrieved successfully + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/SameHostnameResponse' + - $ref: '#/components/schemas/DifferentHostnameResponse' + examples: + same_hostname: + summary: Same hostname response + value: + redirectTo: "/fr/page-slug" + different_hostname: + summary: Different hostname response + value: + redirectTo: "https://fr.example.com/french-example-page?aposCrossDomainSessionToken=generated_token" + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + + /@apostrophecms/i18n/exist-in-locale: + post: + tags: + - Internationalization + summary: Check document existence in locale + description: | + Returns arrays of original document IDs, new locale IDs, and aposDocIds + for an array of document IDs in a specified locale and mode. + parameters: + - name: ids + in: query + description: Required. Array of document IDs to check in the specified locale + required: true + schema: + type: array + items: + type: string + example: ["cloydg3ka0005qcls5vmg8sb9", "cloydg3ka0005qcls5vmg8sb8"] + - name: locale + in: query + description: Required. The locale in which to check for the document IDs + required: true + schema: + type: string + example: "fr" + - name: mode + in: query + description: Required. The mode (draft or published) in which to check for the document IDs + required: true + schema: + type: string + enum: [draft, published] + example: "published" + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ExistInLocaleRequest' + example: + ids: ["cloydg3ka0005qcls5vmg8sb9", "cloydg3ka0005qcls5vmg8sb8"] + locale: "fr" + mode: "published" + responses: + '200': + description: Document existence check completed successfully + content: + application/json: + schema: + $ref: '#/components/schemas/ExistInLocaleResponse' + example: + originalLocaleIds: ["cloydg3ka0005qcls5vmg8sb9:en:published", "cloydg3ka0005qcls5vmg8sb8:en:published"] + newLocaleIds: ["cloydg3ka0005qcls5vmg8sb9:fr:published", "cloydg3ka0005qcls5vmg8sb8:fr:published"] + aposDocIds: ["cloydg3ka0005qcls5vmg8sb9", "cloydg3ka0005qcls5vmg8sb8"] + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] diff --git a/docs/reference/api/api-explorer.md b/docs/reference/api/api-explorer.md new file mode 100644 index 00000000..a35a0a0a --- /dev/null +++ b/docs/reference/api/api-explorer.md @@ -0,0 +1,117 @@ +--- +title: ApostropheCMS API Documentation +description: Complete REST API reference for ApostropheCMS headless CMS +--- + +# ApostropheCMS REST API OpenAPI Specification + +ApostropheCMS provides a comprehensive REST API for headless CMS functionality, perfect for agencies managing multiple client sites. + +## What is the ApostropheCMS API? + +The ApostropheCMS API is a RESTful interface that allows developers to: +- Create and manage content programmatically +- Build headless applications with any frontend framework +- Integrate with third-party services and tools +- Manage multisite configurations for agency workflows + +## OpenAPI Specification + +Our API follows OpenAPI 3.0 standards, making it compatible with modern development tools and AI assistants. + +### What is OpenAPI? +OpenAPI (formerly Swagger) is a standardized way to describe REST APIs. Our specification includes: +- All available endpoints and methods +- Request/response schemas and examples +- Authentication requirements +- Error codes and responses + +### Downloads +- [OpenAPI YAML Specification](/apostrophecms-openapi.yaml){download="apostrophecms-openapi.yaml"} + +## How to Use This Specification + +### For Developers +- **Import into Postman**: Use our spec to auto-generate API collections +- **Generate client libraries**: Create SDKs for JavaScript, Python, PHP, etc. +- **API exploration**: Browse all endpoints interactively in our [sandbox](/reference/api/sandbox) + +### For AI Integration +Our OpenAPI spec enables: +- **ChatGPT plugins**: Compatible with OpenAI's plugin system +- **Documentation chatbots**: Use with RAG systems for automated API support +- **Code generation**: AI coding tools can generate accurate ApostropheCMS API code + +[Continue to the API Sandbox →](/reference/api/sandbox) or start learning more: + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/reference/api/sandbox.md b/docs/reference/api/sandbox.md new file mode 100644 index 00000000..3612ef80 --- /dev/null +++ b/docs/reference/api/sandbox.md @@ -0,0 +1,38 @@ +--- +title: ApostropheCMS API Reference - Interactive Explorer +description: Interactive OpenAPI documentation for ApostropheCMS REST API +--- + +# Interactive API Reference + +> **💡 Testing Live APIs**: This explorer connects to `localhost:3000` for demonstration. You can test with API key or bearer token authentication, but not session cookies. +> +> To test against your production ApostropheCMS site or use session authentication, [download our OpenAPI spec](/apostrophecms-openapi.yaml) and update: +> - Server URL (change `https://your-site.com` to your actual domain) +> - Session cookie name (change `project-shortname.sid` to `yourproject.sid`) + + + +## Testing Against Your Own Site + +1. **Download**: Get our [OpenAPI specification](/openapi.yaml){download="apostrophecms-openapi.yaml"} +2. **Import**: Load it into Postman, Insomnia, or similar tools +3. **Configure**: Set your server URL and authentication token +4. **Test**: Make live API calls to your ApostropheCMS instance + + +## About This Reference + +This interactive documentation is generated from our [OpenAPI specification](/openapi.yaml). You can: + +- **Test endpoints live**: Make real API calls (with authentication) +- **View request/response examples**: See exactly what data to send and expect +- **Understand schemas**: Explore all data models and field requirements +- **Copy code samples**: Get ready-to-use code in multiple languages + +## Need the Raw Specification? + +- [Download YAML format](/openapi.yaml) - For human reading and editing + +## Start learning about the ApostropheCMS API +[Learn more about API authentication →](/reference/api/authentication) diff --git a/package-lock.json b/package-lock.json index 05027afc..53f09026 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "jsdom": "^22.1.0", "marked": "^12.0.2", "socket.io-client": "^4.7.5", + "swagger-ui-dist": "^5.22.0", "uuid": "^10.0.0", "vitepress-plugin-pagefind": "^0.2.4", "vue": "^3.3.4", @@ -1613,6 +1614,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@scarf/scarf": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz", + "integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==", + "hasInstallScript": true, + "license": "Apache-2.0" + }, "node_modules/@shikijs/core": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-2.5.0.tgz", @@ -8312,6 +8320,15 @@ "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", "dev": true }, + "node_modules/swagger-ui-dist": { + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.22.0.tgz", + "integrity": "sha512-8YlCSxiyb8uPFa7qoB1lRHYr1PBbT1NuV9RvQdFFPFPudRBTPf9coU5jl02KhzvrtmTEw4jXRgb0kg8pJvVuWQ==", + "license": "Apache-2.0", + "dependencies": { + "@scarf/scarf": "=1.4.0" + } + }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", diff --git a/package.json b/package.json index d95ef0d2..9406ecf2 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "jsdom": "^22.1.0", "marked": "^12.0.2", "socket.io-client": "^4.7.5", + "swagger-ui-dist": "^5.22.0", "uuid": "^10.0.0", "vitepress-plugin-pagefind": "^0.2.4", "vue": "^3.3.4", @@ -45,4 +46,4 @@ "vitepress": "^1.0.0", "vitepress-plugin-search": "1.0.4-alpha.22" } -} \ No newline at end of file +} From 8bbdfc1b50c9b384d1906f10293c58ad8c620e00 Mon Sep 17 00:00:00 2001 From: Robert Means Date: Wed, 4 Jun 2025 05:48:32 -0400 Subject: [PATCH 2/8] Update yaml file --- docs/public/apostrophecms-openapi.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/public/apostrophecms-openapi.yaml b/docs/public/apostrophecms-openapi.yaml index 9ce4f4df..43e10ed4 100644 --- a/docs/public/apostrophecms-openapi.yaml +++ b/docs/public/apostrophecms-openapi.yaml @@ -45,10 +45,11 @@ info: url: https://github.com/apostrophecms/apostrophe/blob/main/LICENSE.md servers: - - url: https://your-site.com/api/v1 - description: Production server (not for online use) - url: http://localhost:3000/api/v1 description: Development server + - url: https://your-site.com/api/v1 + description: Production server (not for online use) + components: securitySchemes: From a570f5e4ea9f85b1023adb732121026f12672501 Mon Sep 17 00:00:00 2001 From: Robert Means Date: Wed, 4 Jun 2025 05:48:46 -0400 Subject: [PATCH 3/8] Clarify sandbox --- docs/reference/api/sandbox.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/docs/reference/api/sandbox.md b/docs/reference/api/sandbox.md index 3612ef80..b1214735 100644 --- a/docs/reference/api/sandbox.md +++ b/docs/reference/api/sandbox.md @@ -5,11 +5,7 @@ description: Interactive OpenAPI documentation for ApostropheCMS REST API # Interactive API Reference -> **💡 Testing Live APIs**: This explorer connects to `localhost:3000` for demonstration. You can test with API key or bearer token authentication, but not session cookies. -> -> To test against your production ApostropheCMS site or use session authentication, [download our OpenAPI spec](/apostrophecms-openapi.yaml) and update: -> - Server URL (change `https://your-site.com` to your actual domain) -> - Session cookie name (change `project-shortname.sid` to `yourproject.sid`) +> **💡 Sandbox Testing**: This online explorer can connect to a project running at `localhost:3000` on your workstation to test standard API routes. You can test with API key or bearer token authentication, but not session cookies. @@ -18,17 +14,19 @@ description: Interactive OpenAPI documentation for ApostropheCMS REST API 1. **Download**: Get our [OpenAPI specification](/openapi.yaml){download="apostrophecms-openapi.yaml"} 2. **Import**: Load it into Postman, Insomnia, or similar tools 3. **Configure**: Set your server URL and authentication token -4. **Test**: Make live API calls to your ApostropheCMS instance + - Server URL (change `https://your-site.com` to your actual domain) + - Session cookie name (change `project-shortname.sid` to `yourproject.sid`) +4. **Test**: Make live API calls to your ApostropheCMS instance, either locally or your hosted site ## About This Reference This interactive documentation is generated from our [OpenAPI specification](/openapi.yaml). You can: -- **Test endpoints live**: Make real API calls (with authentication) +- **Test endpoints live**: Make real API calls to your locally running project (with authentication) - **View request/response examples**: See exactly what data to send and expect - **Understand schemas**: Explore all data models and field requirements -- **Copy code samples**: Get ready-to-use code in multiple languages +- **Copy code samples**: Get ready-to-use code ## Need the Raw Specification? From 4bbea43e8a066cb13777a3f10bd9785abc297dae Mon Sep 17 00:00:00 2001 From: Robert Means Date: Fri, 13 Jun 2025 09:43:54 -0400 Subject: [PATCH 4/8] add dark stylings --- docs/.vitepress/theme/styles/index.styl | 1 + docs/.vitepress/theme/styles/swagger.styl | 690 ++++++++++++++ package-lock.json | 1049 +++++++++++---------- 3 files changed, 1252 insertions(+), 488 deletions(-) create mode 100644 docs/.vitepress/theme/styles/swagger.styl diff --git a/docs/.vitepress/theme/styles/index.styl b/docs/.vitepress/theme/styles/index.styl index 33c9ba61..961c3594 100644 --- a/docs/.vitepress/theme/styles/index.styl +++ b/docs/.vitepress/theme/styles/index.styl @@ -9,3 +9,4 @@ @import 'sidebar.styl'; @import 'aside.styl'; @import 'youtube.styl'; +@import 'swagger.styl'; diff --git a/docs/.vitepress/theme/styles/swagger.styl b/docs/.vitepress/theme/styles/swagger.styl new file mode 100644 index 00000000..a23bd247 --- /dev/null +++ b/docs/.vitepress/theme/styles/swagger.styl @@ -0,0 +1,690 @@ +/* Refactored Swagger UI Dark Mode */ +/* Using consistent color palette and better organization */ + +/* === COLOR VARIABLES === */ +/* + Background: #0f0f23 (deep dark), #1a1a2e (dark), #16213e (medium), #2a2a40 (light) + Text: #ffffff (primary), #e2e8f0 (secondary), #94a3b8 (muted), #64748b (subtle) + Accent: #60a5fa (blue), #34d399 (green), #f59e0b (amber), #ef4444 (red) +*/ + +/* === BASE CONTAINER === */ +html.dark #swagger-ui { + background-color: #0f0f23; + color: #e2e8f0; +} + +/* === TOPBAR === */ +html.dark #swagger-ui .topbar { + background-color: #1a1a2e; + border-bottom: 1px solid #2a2a40; +} + +/* === OPERATION BLOCKS === */ +html.dark #swagger-ui .opblock { + background-color: #1a1a2e; + border: 1px solid #2a2a40; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); +} + +html.dark #swagger-ui .opblock-summary-method, +html.dark #swagger-ui .opblock-summary-description, +html.dark #swagger-ui .opblock-title { + color: #ffffff; +} + +html.dark #swagger-ui .opblock-description-wrapper p, +html.dark #swagger-ui .opblock-description-wrapper h2, +html.dark #swagger-ui .opblock-description-wrapper h3, +html.dark #swagger-ui .opblock-description-wrapper h4 { + color: #e2e8f0; +} + +html.dark #swagger-ui .opblock-section-header { + background-color: #2a2a40; + color: #ffffff; + border-bottom: 1px solid #374151; +} + +html.dark #swagger-ui .opblock-control-arrow { + color: #94a3b8; +} + +html.dark #swagger-ui .opblock-control-arrow svg path { + fill: currentColor; +} + +html.dark #swagger-ui .expand-operation { + color: #94a3b8; +} + +html.dark #swagger-ui .expand-operation svg path { + fill: currentColor; +} + +/* === RESPONSES === */ +html.dark #swagger-ui .responses-inner, +html.dark #swagger-ui .response-col_description, +html.dark #swagger-ui .response-col_status, +html.dark #swagger-ui .response-col_links { + background-color: #16213e; + color: #e2e8f0; +} + +html.dark #swagger-ui .responses-inner h2, +html.dark #swagger-ui .responses-inner h3, +html.dark #swagger-ui .responses-inner h4, +html.dark #swagger-ui .responses-inner h5, +html.dark #swagger-ui .responses-inner h6, +html.dark #swagger-ui .responses-inner p { + color: #e2e8f0; +} + +/* === TYPOGRAPHY === */ +html.dark #swagger-ui h1, +html.dark #swagger-ui h2, +html.dark #swagger-ui h3, +html.dark #swagger-ui h4, +html.dark #swagger-ui h5, +html.dark #swagger-ui h6 { + color: #ffffff; +} + +html.dark #swagger-ui p { + color: #e2e8f0; +} + +/* === LINKS === */ +html.dark #swagger-ui a { + color: #60a5fa; + transition: color 0.2s ease; +} + +html.dark #swagger-ui a:hover { + color: #93c5fd; +} + +/* === RENDERED MARKDOWN === */ +html.dark #swagger-ui .renderedMarkdown { + color: #e2e8f0; +} + +html.dark #swagger-ui .renderedMarkdown h1, +html.dark #swagger-ui .renderedMarkdown h2, +html.dark #swagger-ui .renderedMarkdown h3, +html.dark #swagger-ui .renderedMarkdown h4, +html.dark #swagger-ui .renderedMarkdown h5, +html.dark #swagger-ui .renderedMarkdown h6 { + color: #ffffff; +} + +html.dark #swagger-ui .renderedMarkdown a { + color: #60a5fa; +} + +html.dark #swagger-ui .renderedMarkdown a:hover { + color: #93c5fd; +} + +html.dark #swagger-ui .renderedMarkdown p { + color: #e2e8f0; +} + +html.dark #swagger-ui .renderedMarkdown code { + background-color: #2a2a40; + color: #fbbf24; + padding: 2px 4px; + border-radius: 3px; +} + +html.dark #swagger-ui .renderedMarkdown li, +html.dark #swagger-ui .renderedMarkdown ul, +html.dark #swagger-ui .renderedMarkdown ol, +html.dark #swagger-ui li, +html.dark #swagger-ui ul, +html.dark #swagger-ui ol { + color: #e2e8f0; +} + +/* === TABLES === */ +html.dark #swagger-ui table { + background-color: #1a1a2e; + border: 1px solid #2a2a40; +} + +html.dark #swagger-ui table thead tr th, +html.dark #swagger-ui table.headers td { + color: #ffffff; + background-color: #2a2a40; + border-bottom: 1px solid #374151; +} + +html.dark #swagger-ui table tbody tr { + border-bottom: 1px solid #2a2a40; +} + +html.dark #swagger-ui table tbody tr:hover { + background-color: rgba(42, 42, 64, 0.3); +} + +/* === PARAMETERS === */ +html.dark #swagger-ui td .parameter__name, +html.dark #swagger-ui td .parameter__type, +html.dark #swagger-ui td .parameter__in { + color: #e2e8f0; +} + +html.dark #swagger-ui .parameter__name.required:after { + color: #ef4444; +} + +/* === EXAMPLES === */ +html.dark #swagger-ui .examples-select__section-label { + color: #94a3b8; +} + +html.dark #swagger-ui .example__title { + color: #ffffff; +} + +/* === FORM CONTROLS === */ +html.dark #swagger-ui input[type="text"], +html.dark #swagger-ui input[type="number"], +html.dark #swagger-ui textarea, +html.dark #swagger-ui select { + background-color: #1a1a2e; + color: #e2e8f0; + border: 1px solid #2a2a40; + border-radius: 4px; +} + +/* Fix for select dropdown arrows */ +html.dark #swagger-ui select { + /* Remove default arrow */ + appearance: none; + -webkit-appearance: none; + -moz-appearance: none; + + /* Add custom arrow using properly encoded SVG */ + background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23e2e8f0' d='M6 8L2 4h8z'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right 8px center; + background-size: 12px; + padding-right: 32px; +} + +/* Specific targeting for server dropdown */ +html.dark #swagger-ui .scheme-container select, +html.dark #swagger-ui .servers select, +html.dark #swagger-ui .servers-title + select, +html.dark #swagger-ui [class*="server"] select { + appearance: none !important; + -webkit-appearance: none !important; + -moz-appearance: none !important; + background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23e2e8f0' d='M6 8L2 4h8z'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-position: right 8px center !important; + background-size: 12px !important; + padding-right: 32px !important; +} + +html.dark #swagger-ui input[type="text"]:focus, +html.dark #swagger-ui input[type="number"]:focus, +html.dark #swagger-ui textarea:focus, +html.dark #swagger-ui select:focus { + border-color: #60a5fa; + box-shadow: 0 0 0 2px rgba(96, 165, 250, 0.2); + outline: none; +} + +html.dark #swagger-ui input[type="text"]:disabled, +html.dark #swagger-ui input[type="number"]:disabled, +html.dark #swagger-ui textarea:disabled { + background-color: #16213e; + color: #64748b; + cursor: not-allowed; +} + +/* === BUTTONS === */ +html.dark #swagger-ui .try-out__btn { + background-color: #60a5fa; + color: #ffffff; + border: none; + border-radius: 4px; + transition: background-color 0.2s ease; +} + +html.dark #swagger-ui .try-out__btn:hover { + background-color: #3b82f6; +} + +html.dark #swagger-ui .authorization__btn { + color: #94a3b8; + background-color: transparent; + border: 1px solid #2a2a40; +} + +html.dark #swagger-ui .authorization__btn:hover { + color: #60a5fa; + border-color: #60a5fa; +} + +html.dark #swagger-ui .authorization__btn svg path { + fill: currentColor !important; +} + +/* === SCHEME CONTAINER === */ +html.dark #swagger-ui .scheme-container { + background-color: #1a1a2e; + border: 1px solid #2a2a40; +} + +html.dark #swagger-ui .servers-title { + color: #ffffff; +} + +/* === MODELS SECTION === */ +html.dark #swagger-ui .model-box { + background-color: #1a1a2e; + color: #e2e8f0; + border: 1px solid #2a2a40; + border-radius: 6px; +} + +html.dark #swagger-ui .model-box .arrow svg path { + fill: #94a3b8; +} + +/* Model title and text sizing */ +html.dark #swagger-ui .model-title, +html.dark #swagger-ui .model-title__text { + color: #ffffff; + font-weight: 700; + font-size: 18px; /* Increased from 14px for better readability */ + line-height: 1.4; +} + +/* Model box control button */ +html.dark #swagger-ui .model-box-control { + background: none; + border: none; + color: inherit; + font-family: inherit; + display: flex; + align-items: center; + width: 100%; + text-align: left; + cursor: pointer; + gap: 6px; /* Add consistent spacing between elements */ +} + +/* Collapsed state ellipsis [...] */ +html.dark #swagger-ui .model-box-control span:last-child, +html.dark #swagger-ui .model button span:last-child { + color: #94a3b8; + font-size: 18px; /* Match the title size */ + margin-left: 0; /* Remove margin since we're using gap */ +} + +/* Better toggle arrow alignment */ +html.dark #swagger-ui .model-toggle { + font-size: 10px; + position: relative; + top: 0; /* Reset top positioning */ + display: inline-flex; /* Use inline-flex for better alignment */ + align-items: center; + margin: 0; /* Reset margin */ + cursor: pointer; + transition: transform 0.15s ease-in; + transform: rotate(90deg); + transform-origin: center; +} + +html.dark #swagger-ui .property { + color: #e2e8f0; +} + +html.dark #swagger-ui .prop-type { + color: #a78bfa; + font-weight: 500; +} + +html.dark #swagger-ui .prop-format { + color: #fbbf24; +} + +html.dark #swagger-ui .prop-name { + color: #ffffff; + font-weight: 500; +} + +html.dark #swagger-ui .prop-enum { + color: #34d399; +} + +/* === ENHANCED MODELS SECTION === */ +html.dark #swagger-ui .model { + font-size: 12px; + font-weight: 300; + color: #e2e8f0; +} + +html.dark #swagger-ui .model .deprecated span, +html.dark #swagger-ui .model .deprecated td { + color: #64748b !important; +} + +html.dark #swagger-ui .model .deprecated > td:first-of-type { + text-decoration: line-through; +} + +html.dark #swagger-ui .model-toggle { + font-size: 10px; + position: relative; + top: 6px; + display: inline-block; + margin: auto 0.3em; + cursor: pointer; + transition: transform 0.15s ease-in; + transform: rotate(90deg); + transform-origin: 50% 50%; +} + +html.dark #swagger-ui .model-toggle.collapsed { + transform: rotate(0deg); +} + +html.dark #swagger-ui .model-toggle:after { + display: block; + width: 20px; + height: 20px; + content: ""; + background: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='%23e2e8f0' d='M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z'/%3E%3C/svg%3E") center no-repeat; + background-size: 100%; +} + +html.dark #swagger-ui .model-jump-to-path { + position: relative; + cursor: pointer; +} + +html.dark #swagger-ui .model-jump-to-path .view-line-link { + position: absolute; + top: -0.4em; + cursor: pointer; + color: #60a5fa; +} + +html.dark #swagger-ui .model-jump-to-path .view-line-link:hover { + color: #93c5fd; +} + +html.dark #swagger-ui .model-title { + position: relative; + color: #ffffff; +} + +html.dark #swagger-ui .model-title:hover .model-hint { + display: block; +} + +html.dark #swagger-ui .model-hint { + position: absolute; + top: -1.8em; + display: none; + padding: 0.1em 0.5em; + white-space: nowrap; + color: #ffffff; + border-radius: 4px; + background: rgba(26, 26, 46, 0.95); + border: 1px solid #2a2a40; + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3); +} + +html.dark #swagger-ui .model p { + margin: 0 0 1em 0; + color: #e2e8f0; +} + +html.dark #swagger-ui .model .property { + color: #94a3b8; + font-style: italic; +} + +html.dark #swagger-ui .model .property.primitive { + color: #64748b; +} + +html.dark #swagger-ui .model .property.primitive.extension { + display: block; +} + +html.dark #swagger-ui .model .property.primitive.extension > td:first-child { + padding-left: 0; + padding-right: 0; + width: auto; +} + +html.dark #swagger-ui .model .property.primitive.extension > td:first-child:after { + content: ":\00a0"; +} + +html.dark #swagger-ui .model .external-docs { + color: #94a3b8; + font-weight: normal; +} + +html.dark #swagger-ui table.model { + background: #1a1a2e; + border: 1px solid #2a2a40; + border-radius: 6px; +} + +html.dark #swagger-ui table.model tr { + border-bottom: 1px solid #2a2a40; +} + +html.dark #swagger-ui table.model tr:last-child { + border-bottom: none; +} + +html.dark #swagger-ui table.model tr.description { + color: #94a3b8; + font-weight: normal; + background: rgba(15, 15, 35, 0.3); +} + +html.dark #swagger-ui table.model tr.description td:first-child { + font-weight: bold; + color: #ffffff; +} + +html.dark #swagger-ui table.model tr.property-row:hover { + background: rgba(42, 42, 64, 0.3); +} + +html.dark #swagger-ui table.model tr.property-row.required td:first-child { + font-weight: bold; + color: #ffffff; +} + +html.dark #swagger-ui table.model tr.property-row td { + vertical-align: top; + padding: 8px 12px; + color: #e2e8f0; +} + +html.dark #swagger-ui table.model tr.property-row td:first-child { + padding-right: 0.2em; +} + +html.dark #swagger-ui table.model tr.property-row .star { + color: #ef4444; +} + +html.dark #swagger-ui table.model tr.extension { + color: #94a3b8; + background: rgba(15, 15, 35, 0.2); +} + +html.dark #swagger-ui table.model tr.extension td:last-child { + vertical-align: top; +} + +html.dark #swagger-ui table.model tr.external-docs { + background: rgba(15, 15, 35, 0.2); +} + +html.dark #swagger-ui table.model tr.external-docs td:first-child { + font-weight: bold; + color: #ffffff; +} + +html.dark #swagger-ui table.model tr .renderedMarkdown { + color: #e2e8f0; +} + +html.dark #swagger-ui table.model tr .renderedMarkdown p:first-child { + margin-top: 0; +} + +html.dark #swagger-ui section.models { + margin: 30px 0; + border: 1px solid rgba(42, 42, 64, 0.6); + border-radius: 6px; + background: #0f0f23; +} + +html.dark #swagger-ui section.models .pointer { + cursor: pointer; +} + +html.dark #swagger-ui section.models.is-open { + padding: 0 0 20px; +} + +html.dark #swagger-ui section.models.is-open h4 { + margin: 0 0 5px 0; + border-bottom: 1px solid rgba(52, 52, 80, 0.5); +} + +html.dark #swagger-ui section.models h4 { + font-size: 18px; + display: flex; + align-items: center; + margin: 0; + padding: 10px 20px 10px 10px; + cursor: pointer; + transition: all 0.2s; + color: #ffffff; +} + +html.dark #swagger-ui section.models h4 svg { + transition: all 0.4s; + fill: #e2e8f0; +} + +html.dark #swagger-ui section.models h4 span { + flex: 1; +} + +html.dark #swagger-ui section.models h4:hover { + background: rgba(42, 42, 64, 0.1); +} + +html.dark #swagger-ui section.models h5 { + font-size: 16px; + margin: 0 0 10px 0; + color: #ffffff; +} + +html.dark #swagger-ui section.models .model-jump-to-path { + position: relative; + top: 5px; +} + +html.dark #swagger-ui section.models .model-jump-to-path .view-line-link { + color: #60a5fa; +} + +html.dark #swagger-ui section.models .model-jump-to-path .view-line-link:hover { + color: #93c5fd; +} + +html.dark #swagger-ui section.models .model-container { + margin: 0 20px 15px; + position: relative; + transition: all 0.5s; + border-radius: 6px; + background: rgba(26, 26, 46, 0.4); + border: 1px solid rgba(42, 42, 64, 0.3); +} + +html.dark #swagger-ui section.models .model-container:hover { + background: rgba(26, 26, 46, 0.6); + border-color: rgba(52, 52, 80, 0.5); +} + +html.dark #swagger-ui section.models .model-container:first-of-type { + margin: 20px; +} + +html.dark #swagger-ui section.models .model-container:last-of-type { + margin: 0 20px; +} + +html.dark #swagger-ui section.models .model-container .models-jump-to-path { + position: absolute; + top: 8px; + right: 5px; + opacity: 0.7; + color: #94a3b8; +} + +html.dark #swagger-ui section.models .model-container .models-jump-to-path:hover { + opacity: 1; + color: #60a5fa; +} + +html.dark #swagger-ui section.models .model-box { + background: rgba(26, 26, 46, 0.6); + border: 1px solid rgba(42, 42, 64, 0.4); +} + +html.dark #swagger-ui .model-box { + padding: 12px; + display: inline-block; + border-radius: 6px; + background: rgba(26, 26, 46, 0.8); + border: 1px solid rgba(42, 42, 64, 0.5); +} + +html.dark #swagger-ui .model-box .model-jump-to-path { + position: relative; + top: 4px; +} + +html.dark #swagger-ui .model-box .model-jump-to-path .view-line-link { + color: #60a5fa; +} + +html.dark #swagger-ui .model-box .model-jump-to-path .view-line-link:hover { + color: #93c5fd; +} + +html.dark #swagger-ui .model-box.deprecated { + opacity: 0.4; + background: rgba(26, 26, 46, 0.3); +} + +html.dark #swagger-ui .model-deprecated-warning { + font-size: 16px; + font-weight: 600; + margin-right: 1em; + color: #fca5a5; +} + +html.dark #swagger-ui span > span.model .brace-close { + padding: 0 0 0 10px; + color: #e2e8f0; +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 53f09026..39b4c693 100644 --- a/package-lock.json +++ b/package-lock.json @@ -87,41 +87,41 @@ } }, "node_modules/@algolia/client-abtesting": { - "version": "5.20.3", - "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.20.3.tgz", - "integrity": "sha512-wPOzHYSsW+H97JkBLmnlOdJSpbb9mIiuNPycUCV5DgzSkJFaI/OFxXfZXAh1gqxK+hf0miKue1C9bltjWljrNA==", + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.27.0.tgz", + "integrity": "sha512-SITU5umoknxETtw67TxJu9njyMkWiH8pM+Bvw4dzfuIrIAT6Y1rmwV4y0A0didWoT+6xVuammIykbtBMolBcmg==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.20.3", - "@algolia/requester-browser-xhr": "5.20.3", - "@algolia/requester-fetch": "5.20.3", - "@algolia/requester-node-http": "5.20.3" + "@algolia/client-common": "5.27.0", + "@algolia/requester-browser-xhr": "5.27.0", + "@algolia/requester-fetch": "5.27.0", + "@algolia/requester-node-http": "5.27.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-analytics": { - "version": "5.20.3", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.20.3.tgz", - "integrity": "sha512-XE3iduH9lA7iTQacDGofBQyIyIgaX8qbTRRdj1bOCmfzc9b98CoiMwhNwdTifmmMewmN0EhVF3hP8KjKWwX7Yw==", + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.27.0.tgz", + "integrity": "sha512-go1b9qIZK5vYEQ7jD2bsfhhhVsoh9cFxQ5xF8TzTsg2WOCZR3O92oXCkq15SOK0ngJfqDU6a/k0oZ4KuEnih1Q==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.20.3", - "@algolia/requester-browser-xhr": "5.20.3", - "@algolia/requester-fetch": "5.20.3", - "@algolia/requester-node-http": "5.20.3" + "@algolia/client-common": "5.27.0", + "@algolia/requester-browser-xhr": "5.27.0", + "@algolia/requester-fetch": "5.27.0", + "@algolia/requester-node-http": "5.27.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-common": { - "version": "5.20.3", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.20.3.tgz", - "integrity": "sha512-IYRd/A/R3BXeaQVT2805lZEdWo54v39Lqa7ABOxIYnUvX2vvOMW1AyzCuT0U7Q+uPdD4UW48zksUKRixShcWxA==", + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.27.0.tgz", + "integrity": "sha512-tnFOzdNuMzsz93kOClj3fKfuYoF3oYaEB5bggULSj075GJ7HUNedBEm7a6ScrjtnOaOtipbnT7veUpHA4o4wEQ==", "dev": true, "license": "MIT", "engines": { @@ -129,196 +129,196 @@ } }, "node_modules/@algolia/client-insights": { - "version": "5.20.3", - "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.20.3.tgz", - "integrity": "sha512-QGc/bmDUBgzB71rDL6kihI2e1Mx6G6PxYO5Ks84iL3tDcIel1aFuxtRF14P8saGgdIe1B6I6QkpkeIddZ6vWQw==", + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.27.0.tgz", + "integrity": "sha512-y1qgw39qZijjQBXrqZTiwK1cWgWGRiLpJNWBv9w36nVMKfl9kInrfsYmdBAfmlhVgF/+Woe0y1jQ7pa4HyShAw==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.20.3", - "@algolia/requester-browser-xhr": "5.20.3", - "@algolia/requester-fetch": "5.20.3", - "@algolia/requester-node-http": "5.20.3" + "@algolia/client-common": "5.27.0", + "@algolia/requester-browser-xhr": "5.27.0", + "@algolia/requester-fetch": "5.27.0", + "@algolia/requester-node-http": "5.27.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-personalization": { - "version": "5.20.3", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.20.3.tgz", - "integrity": "sha512-zuM31VNPDJ1LBIwKbYGz/7+CSm+M8EhlljDamTg8AnDilnCpKjBebWZR5Tftv/FdWSro4tnYGOIz1AURQgZ+tQ==", + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.27.0.tgz", + "integrity": "sha512-XluG9qPZKEbiLoIfXTKbABsWDNOMPx0t6T2ImJTTeuX+U/zBdmfcqqgcgkqXp+vbXof/XX/4of9Eqo1JaqEmKw==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.20.3", - "@algolia/requester-browser-xhr": "5.20.3", - "@algolia/requester-fetch": "5.20.3", - "@algolia/requester-node-http": "5.20.3" + "@algolia/client-common": "5.27.0", + "@algolia/requester-browser-xhr": "5.27.0", + "@algolia/requester-fetch": "5.27.0", + "@algolia/requester-node-http": "5.27.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-query-suggestions": { - "version": "5.20.3", - "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.20.3.tgz", - "integrity": "sha512-Nn872PuOI8qzi1bxMMhJ0t2AzVBqN01jbymBQOkypvZHrrjZPso3iTpuuLLo9gi3yc/08vaaWTAwJfPhxPwJUw==", + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.27.0.tgz", + "integrity": "sha512-V8/To+SsAl2sdw2AAjeLJuCW1L+xpz+LAGerJK7HKqHzE5yQhWmIWZTzqYQcojkii4iBMYn0y3+uReWqT8XVSQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.20.3", - "@algolia/requester-browser-xhr": "5.20.3", - "@algolia/requester-fetch": "5.20.3", - "@algolia/requester-node-http": "5.20.3" + "@algolia/client-common": "5.27.0", + "@algolia/requester-browser-xhr": "5.27.0", + "@algolia/requester-fetch": "5.27.0", + "@algolia/requester-node-http": "5.27.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-search": { - "version": "5.20.3", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.20.3.tgz", - "integrity": "sha512-9+Fm1ahV8/2goSIPIqZnVitV5yHW5E5xTdKy33xnqGd45A9yVv5tTkudWzEXsbfBB47j9Xb3uYPZjAvV5RHbKA==", + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.27.0.tgz", + "integrity": "sha512-EJJ7WmvmUXZdchueKFCK8UZFyLqy4Hz64snNp0cTc7c0MKaSeDGYEDxVsIJKp15r7ORaoGxSyS4y6BGZMXYuCg==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.20.3", - "@algolia/requester-browser-xhr": "5.20.3", - "@algolia/requester-fetch": "5.20.3", - "@algolia/requester-node-http": "5.20.3" + "@algolia/client-common": "5.27.0", + "@algolia/requester-browser-xhr": "5.27.0", + "@algolia/requester-fetch": "5.27.0", + "@algolia/requester-node-http": "5.27.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/ingestion": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.20.3.tgz", - "integrity": "sha512-5GHNTiZ3saLjTNyr6WkP5hzDg2eFFAYWomvPcm9eHWskjzXt8R0IOiW9kkTS6I6hXBwN5H9Zna5mZDSqqJdg+g==", + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.27.0.tgz", + "integrity": "sha512-xNCyWeqpmEo4EdmpG57Fs1fJIQcPwt5NnJ6MBdXnUdMVXF4f5PHgza+HQWQQcYpCsune96jfmR0v7us6gRIlCw==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.20.3", - "@algolia/requester-browser-xhr": "5.20.3", - "@algolia/requester-fetch": "5.20.3", - "@algolia/requester-node-http": "5.20.3" + "@algolia/client-common": "5.27.0", + "@algolia/requester-browser-xhr": "5.27.0", + "@algolia/requester-fetch": "5.27.0", + "@algolia/requester-node-http": "5.27.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/monitoring": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.20.3.tgz", - "integrity": "sha512-KUWQbTPoRjP37ivXSQ1+lWMfaifCCMzTnEcEnXwAmherS5Tp7us6BAqQDMGOD4E7xyaS2I8pto6WlOzxH+CxmA==", + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.27.0.tgz", + "integrity": "sha512-P0NDiEFyt9UYQLBI0IQocIT7xHpjMpoFN3UDeerbztlkH9HdqT0GGh1SHYmNWpbMWIGWhSJTtz6kSIWvFu4+pw==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.20.3", - "@algolia/requester-browser-xhr": "5.20.3", - "@algolia/requester-fetch": "5.20.3", - "@algolia/requester-node-http": "5.20.3" + "@algolia/client-common": "5.27.0", + "@algolia/requester-browser-xhr": "5.27.0", + "@algolia/requester-fetch": "5.27.0", + "@algolia/requester-node-http": "5.27.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/recommend": { - "version": "5.20.3", - "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.20.3.tgz", - "integrity": "sha512-oo/gG77xTTTclkrdFem0Kmx5+iSRFiwuRRdxZETDjwzCI7svutdbwBgV/Vy4D4QpYaX4nhY/P43k84uEowCE4Q==", + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.27.0.tgz", + "integrity": "sha512-cqfTMF1d1cc7hg0vITNAFxJZas7MJ4Obc36WwkKpY23NOtGb+4tH9X7UKlQa2PmTgbXIANoJ/DAQTeiVlD2I4Q==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.20.3", - "@algolia/requester-browser-xhr": "5.20.3", - "@algolia/requester-fetch": "5.20.3", - "@algolia/requester-node-http": "5.20.3" + "@algolia/client-common": "5.27.0", + "@algolia/requester-browser-xhr": "5.27.0", + "@algolia/requester-fetch": "5.27.0", + "@algolia/requester-node-http": "5.27.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-browser-xhr": { - "version": "5.20.3", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.20.3.tgz", - "integrity": "sha512-BkkW7otbiI/Er1AiEPZs1h7lxbtSO9p09jFhv3/iT8/0Yz0CY79VJ9iq+Wv1+dq/l0OxnMpBy8mozrieGA3mXQ==", + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.27.0.tgz", + "integrity": "sha512-ErenYTcXl16wYXtf0pxLl9KLVxIztuehqXHfW9nNsD8mz9OX42HbXuPzT7y6JcPiWJpc/UU/LY5wBTB65vsEUg==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.20.3" + "@algolia/client-common": "5.27.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-fetch": { - "version": "5.20.3", - "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.20.3.tgz", - "integrity": "sha512-eAVlXz7UNzTsA1EDr+p0nlIH7WFxo7k3NMxYe8p38DH8YVWLgm2MgOVFUMNg9HCi6ZNOi/A2w/id2ZZ4sKgUOw==", + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.27.0.tgz", + "integrity": "sha512-CNOvmXsVi+IvT7z1d+6X7FveVkgEQwTNgipjQCHTIbF9KSMfZR7tUsJC+NpELrm10ALdOMauah84ybs9rw1cKQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.20.3" + "@algolia/client-common": "5.27.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-node-http": { - "version": "5.20.3", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.20.3.tgz", - "integrity": "sha512-FqR3pQPfHfQyX1wgcdK6iyqu86yP76MZd4Pzj1y/YLMj9rRmRCY0E0AffKr//nrOFEwv6uY8BQY4fd9/6b0ZCg==", + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.27.0.tgz", + "integrity": "sha512-Nx9EdLYZDsaYFTthqmc0XcVvsx6jqeEX8fNiYOB5i2HboQwl8pJPj1jFhGqoGd0KG7KFR+sdPO5/e0EDDAru2Q==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.20.3" + "@algolia/client-common": "5.27.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@babel/code-frame": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", + "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.9.tgz", - "integrity": "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==", + "version": "7.27.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.5.tgz", + "integrity": "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==", "license": "MIT", "dependencies": { - "@babel/types": "^7.26.9" + "@babel/types": "^7.27.3" }, "bin": { "parser": "bin/babel-parser.js" @@ -328,13 +328,13 @@ } }, "node_modules/@babel/types": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.9.tgz", - "integrity": "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==", + "version": "7.27.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.6.tgz", + "integrity": "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==", "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -873,9 +873,9 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", - "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", "dev": true, "license": "MIT", "dependencies": { @@ -974,9 +974,9 @@ "license": "BSD-3-Clause" }, "node_modules/@iconify-json/simple-icons": { - "version": "1.2.25", - "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.25.tgz", - "integrity": "sha512-2E1/gOCO97rF6usfhhiXxwzCb+UhdEsxW3lW1Sew+xZY0COY6dp82Z/r1rUt2fWKneWjuoGcNeJHHXQyG8mIuw==", + "version": "1.2.38", + "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.38.tgz", + "integrity": "sha512-mvMeFQgVjoHanQE9Q7ihmriEXAorjLZW+crUgQspDjFpzWuQp2RZMTppl1MN6TQztMVTsNFgF6LDKsp+v1RYRg==", "dev": true, "license": "CC0-1.0", "dependencies": { @@ -1342,9 +1342,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.8.tgz", - "integrity": "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.43.0.tgz", + "integrity": "sha512-Krjy9awJl6rKbruhQDgivNbD1WuLb8xAclM4IR4cN5pHGAs2oIMMQJEiC3IC/9TZJ+QZkmZhlMO/6MBGxPidpw==", "cpu": [ "arm" ], @@ -1356,9 +1356,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.8.tgz", - "integrity": "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.43.0.tgz", + "integrity": "sha512-ss4YJwRt5I63454Rpj+mXCXicakdFmKnUNxr1dLK+5rv5FJgAxnN7s31a5VchRYxCFWdmnDWKd0wbAdTr0J5EA==", "cpu": [ "arm64" ], @@ -1370,9 +1370,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.8.tgz", - "integrity": "sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.43.0.tgz", + "integrity": "sha512-eKoL8ykZ7zz8MjgBenEF2OoTNFAPFz1/lyJ5UmmFSz5jW+7XbH1+MAgCVHy72aG59rbuQLcJeiMrP8qP5d/N0A==", "cpu": [ "arm64" ], @@ -1384,9 +1384,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.8.tgz", - "integrity": "sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.43.0.tgz", + "integrity": "sha512-SYwXJgaBYW33Wi/q4ubN+ldWC4DzQY62S4Ll2dgfr/dbPoF50dlQwEaEHSKrQdSjC6oIe1WgzosoaNoHCdNuMg==", "cpu": [ "x64" ], @@ -1398,9 +1398,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.8.tgz", - "integrity": "sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.43.0.tgz", + "integrity": "sha512-SV+U5sSo0yujrjzBF7/YidieK2iF6E7MdF6EbYxNz94lA+R0wKl3SiixGyG/9Klab6uNBIqsN7j4Y/Fya7wAjQ==", "cpu": [ "arm64" ], @@ -1412,9 +1412,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.8.tgz", - "integrity": "sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.43.0.tgz", + "integrity": "sha512-J7uCsiV13L/VOeHJBo5SjasKiGxJ0g+nQTrBkAsmQBIdil3KhPnSE9GnRon4ejX1XDdsmK/l30IYLiAaQEO0Cg==", "cpu": [ "x64" ], @@ -1426,9 +1426,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.8.tgz", - "integrity": "sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.43.0.tgz", + "integrity": "sha512-gTJ/JnnjCMc15uwB10TTATBEhK9meBIY+gXP4s0sHD1zHOaIh4Dmy1X9wup18IiY9tTNk5gJc4yx9ctj/fjrIw==", "cpu": [ "arm" ], @@ -1440,9 +1440,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.8.tgz", - "integrity": "sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.43.0.tgz", + "integrity": "sha512-ZJ3gZynL1LDSIvRfz0qXtTNs56n5DI2Mq+WACWZ7yGHFUEirHBRt7fyIk0NsCKhmRhn7WAcjgSkSVVxKlPNFFw==", "cpu": [ "arm" ], @@ -1454,9 +1454,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.8.tgz", - "integrity": "sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.43.0.tgz", + "integrity": "sha512-8FnkipasmOOSSlfucGYEu58U8cxEdhziKjPD2FIa0ONVMxvl/hmONtX/7y4vGjdUhjcTHlKlDhw3H9t98fPvyA==", "cpu": [ "arm64" ], @@ -1468,9 +1468,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.8.tgz", - "integrity": "sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.43.0.tgz", + "integrity": "sha512-KPPyAdlcIZ6S9C3S2cndXDkV0Bb1OSMsX0Eelr2Bay4EsF9yi9u9uzc9RniK3mcUGCLhWY9oLr6er80P5DE6XA==", "cpu": [ "arm64" ], @@ -1482,9 +1482,9 @@ ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.8.tgz", - "integrity": "sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.43.0.tgz", + "integrity": "sha512-HPGDIH0/ZzAZjvtlXj6g+KDQ9ZMHfSP553za7o2Odegb/BEfwJcR0Sw0RLNpQ9nC6Gy8s+3mSS9xjZ0n3rhcYg==", "cpu": [ "loong64" ], @@ -1496,9 +1496,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.8.tgz", - "integrity": "sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.43.0.tgz", + "integrity": "sha512-gEmwbOws4U4GLAJDhhtSPWPXUzDfMRedT3hFMyRAvM9Mrnj+dJIFIeL7otsv2WF3D7GrV0GIewW0y28dOYWkmw==", "cpu": [ "ppc64" ], @@ -1510,9 +1510,23 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.8.tgz", - "integrity": "sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.43.0.tgz", + "integrity": "sha512-XXKvo2e+wFtXZF/9xoWohHg+MuRnvO29TI5Hqe9xwN5uN8NKUYy7tXUG3EZAlfchufNCTHNGjEx7uN78KsBo0g==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.43.0.tgz", + "integrity": "sha512-ruf3hPWhjw6uDFsOAzmbNIvlXFXlBQ4nk57Sec8E8rUxs/AI4HD6xmiiasOOx/3QxS2f5eQMKTAwk7KHwpzr/Q==", "cpu": [ "riscv64" ], @@ -1524,9 +1538,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.8.tgz", - "integrity": "sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.43.0.tgz", + "integrity": "sha512-QmNIAqDiEMEvFV15rsSnjoSmO0+eJLoKRD9EAa9rrYNwO/XRCtOGM3A5A0X+wmG+XRrw9Fxdsw+LnyYiZWWcVw==", "cpu": [ "s390x" ], @@ -1538,9 +1552,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.8.tgz", - "integrity": "sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.43.0.tgz", + "integrity": "sha512-jAHr/S0iiBtFyzjhOkAics/2SrXE092qyqEg96e90L3t9Op8OTzS6+IX0Fy5wCt2+KqeHAkti+eitV0wvblEoQ==", "cpu": [ "x64" ], @@ -1552,9 +1566,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.8.tgz", - "integrity": "sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.43.0.tgz", + "integrity": "sha512-3yATWgdeXyuHtBhrLt98w+5fKurdqvs8B53LaoKD7P7H7FKOONLsBVMNl9ghPQZQuYcceV5CDyPfyfGpMWD9mQ==", "cpu": [ "x64" ], @@ -1566,9 +1580,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.8.tgz", - "integrity": "sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.43.0.tgz", + "integrity": "sha512-wVzXp2qDSCOpcBCT5WRWLmpJRIzv23valvcTwMHEobkjippNf+C3ys/+wf07poPkeNix0paTNemB2XrHr2TnGw==", "cpu": [ "arm64" ], @@ -1580,9 +1594,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.8.tgz", - "integrity": "sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.43.0.tgz", + "integrity": "sha512-fYCTEyzf8d+7diCw8b+asvWDCLMjsCEA8alvtAutqJOJp/wL5hs1rWSqJ1vkjgW0L2NB4bsYJrpKkiIPRR9dvw==", "cpu": [ "ia32" ], @@ -1594,9 +1608,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.8.tgz", - "integrity": "sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.43.0.tgz", + "integrity": "sha512-SnGhLiE5rlK0ofq8kzuDkM0g7FN1s5VYY+YSMTibP7CqShxCQvqtNxTARS4xX4PFJfHjG0ZQYX9iGzI3FQh5Aw==", "cpu": [ "x64" ], @@ -1736,9 +1750,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", "dev": true, "license": "MIT" }, @@ -1840,9 +1854,9 @@ "license": "MIT" }, "node_modules/@types/web-bluetooth": { - "version": "0.0.20", - "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz", - "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==", + "version": "0.0.21", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", + "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==", "dev": true, "license": "MIT" }, @@ -1854,85 +1868,85 @@ "license": "ISC" }, "node_modules/@vue/compiler-core": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.13.tgz", - "integrity": "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==", + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.16.tgz", + "integrity": "sha512-AOQS2eaQOaaZQoL1u+2rCJIKDruNXVBZSiUD3chnUrsoX5ZTQMaCvXlWNIfxBJuU15r1o7+mpo5223KVtIhAgQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.25.3", - "@vue/shared": "3.5.13", + "@babel/parser": "^7.27.2", + "@vue/shared": "3.5.16", "entities": "^4.5.0", "estree-walker": "^2.0.2", - "source-map-js": "^1.2.0" + "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-dom": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz", - "integrity": "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==", + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.16.tgz", + "integrity": "sha512-SSJIhBr/teipXiXjmWOVWLnxjNGo65Oj/8wTEQz0nqwQeP75jWZ0n4sF24Zxoht1cuJoWopwj0J0exYwCJ0dCQ==", "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.13", - "@vue/shared": "3.5.13" + "@vue/compiler-core": "3.5.16", + "@vue/shared": "3.5.16" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz", - "integrity": "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==", + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.16.tgz", + "integrity": "sha512-rQR6VSFNpiinDy/DVUE0vHoIDUF++6p910cgcZoaAUm3POxgNOOdS/xgoll3rNdKYTYPnnbARDCZOyZ+QSe6Pw==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.25.3", - "@vue/compiler-core": "3.5.13", - "@vue/compiler-dom": "3.5.13", - "@vue/compiler-ssr": "3.5.13", - "@vue/shared": "3.5.13", + "@babel/parser": "^7.27.2", + "@vue/compiler-core": "3.5.16", + "@vue/compiler-dom": "3.5.16", + "@vue/compiler-ssr": "3.5.16", + "@vue/shared": "3.5.16", "estree-walker": "^2.0.2", - "magic-string": "^0.30.11", - "postcss": "^8.4.48", - "source-map-js": "^1.2.0" + "magic-string": "^0.30.17", + "postcss": "^8.5.3", + "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz", - "integrity": "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==", + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.16.tgz", + "integrity": "sha512-d2V7kfxbdsjrDSGlJE7my1ZzCXViEcqN6w14DOsDrUCHEA6vbnVCpRFfrc4ryCP/lCKzX2eS1YtnLE/BuC9f/A==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.13", - "@vue/shared": "3.5.13" + "@vue/compiler-dom": "3.5.16", + "@vue/shared": "3.5.16" } }, "node_modules/@vue/devtools-api": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.2.tgz", - "integrity": "sha512-1syn558KhyN+chO5SjlZIwJ8bV/bQ1nOVTG66t2RbG66ZGekyiYNmRO7X9BJCXQqPsFHlnksqvPhce2qpzxFnA==", + "version": "7.7.6", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.6.tgz", + "integrity": "sha512-b2Xx0KvXZObePpXPYHvBRRJLDQn5nhKjXh7vUhMEtWxz1AYNFOVIsh5+HLP8xDGL7sy+Q7hXeUxPHB/KgbtsPw==", "dev": true, "license": "MIT", "dependencies": { - "@vue/devtools-kit": "^7.7.2" + "@vue/devtools-kit": "^7.7.6" } }, "node_modules/@vue/devtools-kit": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.2.tgz", - "integrity": "sha512-CY0I1JH3Z8PECbn6k3TqM1Bk9ASWxeMtTCvZr7vb+CHi+X/QwQm5F1/fPagraamKMAHVfuuCbdcnNg1A4CYVWQ==", + "version": "7.7.6", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.6.tgz", + "integrity": "sha512-geu7ds7tem2Y7Wz+WgbnbZ6T5eadOvozHZ23Atk/8tksHMFOFylKi1xgGlQlVn0wlkEf4hu+vd5ctj1G4kFtwA==", "dev": true, "license": "MIT", "dependencies": { - "@vue/devtools-shared": "^7.7.2", - "birpc": "^0.2.19", + "@vue/devtools-shared": "^7.7.6", + "birpc": "^2.3.0", "hookable": "^5.5.3", "mitt": "^3.0.1", "perfect-debounce": "^1.0.0", "speakingurl": "^14.0.1", - "superjson": "^2.2.1" + "superjson": "^2.2.2" } }, "node_modules/@vue/devtools-shared": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.2.tgz", - "integrity": "sha512-uBFxnp8gwW2vD6FrJB8JZLUzVb6PNRG0B0jBnHsOH8uKyva2qINY8PTF5Te4QlTbMDqU5K6qtJDr6cNsKWhbOA==", + "version": "7.7.6", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.6.tgz", + "integrity": "sha512-yFEgJZ/WblEsojQQceuyK6FzpFDx4kqrz2ohInxNj5/DnhoX023upTv4OD6lNPLAA5LLkbwPVb10o/7b+Y4FVA==", "dev": true, "license": "MIT", "dependencies": { @@ -1940,65 +1954,65 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.13.tgz", - "integrity": "sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==", + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.16.tgz", + "integrity": "sha512-FG5Q5ee/kxhIm1p2bykPpPwqiUBV3kFySsHEQha5BJvjXdZTUfmya7wP7zC39dFuZAcf/PD5S4Lni55vGLMhvA==", "license": "MIT", "dependencies": { - "@vue/shared": "3.5.13" + "@vue/shared": "3.5.16" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.13.tgz", - "integrity": "sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==", + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.16.tgz", + "integrity": "sha512-bw5Ykq6+JFHYxrQa7Tjr+VSzw7Dj4ldR/udyBZbq73fCdJmyy5MPIFR9IX/M5Qs+TtTjuyUTCnmK3lWWwpAcFQ==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.13", - "@vue/shared": "3.5.13" + "@vue/reactivity": "3.5.16", + "@vue/shared": "3.5.16" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.13.tgz", - "integrity": "sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==", + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.16.tgz", + "integrity": "sha512-T1qqYJsG2xMGhImRUV9y/RseB9d0eCYZQ4CWca9ztCuiPj/XWNNN+lkNBuzVbia5z4/cgxdL28NoQCvC0Xcfww==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.13", - "@vue/runtime-core": "3.5.13", - "@vue/shared": "3.5.13", + "@vue/reactivity": "3.5.16", + "@vue/runtime-core": "3.5.16", + "@vue/shared": "3.5.16", "csstype": "^3.1.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.13.tgz", - "integrity": "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==", + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.16.tgz", + "integrity": "sha512-BrX0qLiv/WugguGsnQUJiYOE0Fe5mZTwi6b7X/ybGB0vfrPH9z0gD/Y6WOR1sGCgX4gc25L1RYS5eYQKDMoNIg==", "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.13", - "@vue/shared": "3.5.13" + "@vue/compiler-ssr": "3.5.16", + "@vue/shared": "3.5.16" }, "peerDependencies": { - "vue": "3.5.13" + "vue": "3.5.16" } }, "node_modules/@vue/shared": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.13.tgz", - "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==", + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.16.tgz", + "integrity": "sha512-c/0fWy3Jw6Z8L9FmTyYfkpM5zklnqqa9+a6dz3DvONRKW2NEbh46BP0FHuLFSWi2TnQEtp91Z6zOWNrU6QiyPg==", "license": "MIT" }, "node_modules/@vueuse/core": { - "version": "12.7.0", - "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-12.7.0.tgz", - "integrity": "sha512-jtK5B7YjZXmkGNHjviyGO4s3ZtEhbzSgrbX+s5o+Lr8i2nYqNyHuPVOeTdM1/hZ5Tkxg/KktAuAVDDiHMraMVA==", + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-12.8.2.tgz", + "integrity": "sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/web-bluetooth": "^0.0.20", - "@vueuse/metadata": "12.7.0", - "@vueuse/shared": "12.7.0", + "@types/web-bluetooth": "^0.0.21", + "@vueuse/metadata": "12.8.2", + "@vueuse/shared": "12.8.2", "vue": "^3.5.13" }, "funding": { @@ -2006,14 +2020,14 @@ } }, "node_modules/@vueuse/integrations": { - "version": "12.7.0", - "resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-12.7.0.tgz", - "integrity": "sha512-IEq7K4bCl7mn3uKJaWtNXnd1CAPaHLUMuyj5K1/k/pVcItt0VONZW8xiGxdIovJcQjkzOHjImhX5t6gija+0/g==", + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-12.8.2.tgz", + "integrity": "sha512-fbGYivgK5uBTRt7p5F3zy6VrETlV9RtZjBqd1/HxGdjdckBgBM4ugP8LHpjolqTj14TXTxSK1ZfgPbHYyGuH7g==", "dev": true, "license": "MIT", "dependencies": { - "@vueuse/core": "12.7.0", - "@vueuse/shared": "12.7.0", + "@vueuse/core": "12.8.2", + "@vueuse/shared": "12.8.2", "vue": "^3.5.13" }, "funding": { @@ -2073,9 +2087,9 @@ } }, "node_modules/@vueuse/metadata": { - "version": "12.7.0", - "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-12.7.0.tgz", - "integrity": "sha512-4VvTH9mrjXqFN5LYa5YfqHVRI6j7R00Vy4995Rw7PQxyCL3z0Lli86iN4UemWqixxEvYfRjG+hF9wL8oLOn+3g==", + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-12.8.2.tgz", + "integrity": "sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A==", "dev": true, "license": "MIT", "funding": { @@ -2083,9 +2097,9 @@ } }, "node_modules/@vueuse/shared": { - "version": "12.7.0", - "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-12.7.0.tgz", - "integrity": "sha512-coLlUw2HHKsm7rPN6WqHJQr18WymN4wkA/3ThFaJ4v4gWGWAQQGK+MJxLuJTBs4mojQiazlVWAKNJNpUWGRkNw==", + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-12.8.2.tgz", + "integrity": "sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w==", "dev": true, "license": "MIT", "dependencies": { @@ -2103,9 +2117,9 @@ "license": "BSD-3-Clause" }, "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", "bin": { @@ -2155,25 +2169,25 @@ } }, "node_modules/algoliasearch": { - "version": "5.20.3", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.20.3.tgz", - "integrity": "sha512-iNC6BGvipaalFfDfDnXUje8GUlW5asj0cTMsZJwO/0rhsyLx1L7GZFAY8wW+eQ6AM4Yge2p5GSE5hrBlfSD90Q==", + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.27.0.tgz", + "integrity": "sha512-2PvAgvxxJzA3+dB+ERfS2JPdvUsxNf89Cc2GF5iCcFupTULOwmbfinvqrC4Qj9nHJJDNf494NqEN/1f9177ZTQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-abtesting": "5.20.3", - "@algolia/client-analytics": "5.20.3", - "@algolia/client-common": "5.20.3", - "@algolia/client-insights": "5.20.3", - "@algolia/client-personalization": "5.20.3", - "@algolia/client-query-suggestions": "5.20.3", - "@algolia/client-search": "5.20.3", - "@algolia/ingestion": "1.20.3", - "@algolia/monitoring": "1.20.3", - "@algolia/recommend": "5.20.3", - "@algolia/requester-browser-xhr": "5.20.3", - "@algolia/requester-fetch": "5.20.3", - "@algolia/requester-node-http": "5.20.3" + "@algolia/client-abtesting": "5.27.0", + "@algolia/client-analytics": "5.27.0", + "@algolia/client-common": "5.27.0", + "@algolia/client-insights": "5.27.0", + "@algolia/client-personalization": "5.27.0", + "@algolia/client-query-suggestions": "5.27.0", + "@algolia/client-search": "5.27.0", + "@algolia/ingestion": "1.27.0", + "@algolia/monitoring": "1.27.0", + "@algolia/recommend": "5.27.0", + "@algolia/requester-browser-xhr": "5.27.0", + "@algolia/requester-fetch": "5.27.0", + "@algolia/requester-node-http": "5.27.0" }, "engines": { "node": ">= 14.0.0" @@ -2237,18 +2251,20 @@ } }, "node_modules/array-includes": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", - "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.4", - "is-string": "^1.0.7" + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -2268,18 +2284,19 @@ } }, "node_modules/array.prototype.findlastindex": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", - "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", + "es-abstract": "^1.23.9", "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -2414,9 +2431,9 @@ } }, "node_modules/axios": { - "version": "1.7.9", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", - "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz", + "integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==", "dev": true, "license": "MIT", "dependencies": { @@ -2433,9 +2450,9 @@ "license": "MIT" }, "node_modules/birpc": { - "version": "0.2.19", - "resolved": "https://registry.npmjs.org/birpc/-/birpc-0.2.19.tgz", - "integrity": "sha512-5WeXXAvTmitV1RqJFppT5QtUiz2p1mRSYU000Jkft5ZUCLJIk4uQriYNO50HknxKwM6jd8utNc66K1qGIwwWBQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.3.0.tgz", + "integrity": "sha512-ijbtkn/F3Pvzb6jHypHRyve2QApOCZDR25D/VnkY2G/lBNcXCTsnsCxgY4k4PkVB7zfwzYbY3O9Lcqe3xufS5g==", "dev": true, "license": "MIT", "funding": { @@ -2456,9 +2473,9 @@ "license": "ISC" }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -2502,9 +2519,9 @@ } }, "node_modules/builtins/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, "license": "ISC", "bin": { @@ -2547,14 +2564,14 @@ } }, "node_modules/call-bound": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", - "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "dev": true, "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "get-intrinsic": "^1.2.6" + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" }, "engines": { "node": ">= 0.4" @@ -2669,22 +2686,22 @@ } }, "node_modules/cheerio": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0.tgz", - "integrity": "sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.1.0.tgz", + "integrity": "sha512-+0hMx9eYhJvWbgpKV9hN7jg0JcwydpopZE4hgi+KvQtByZXPp04NiCWU0LzcAbP63abZckIHkTQaXVF52mX3xQ==", "dev": true, "license": "MIT", "dependencies": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", - "domutils": "^3.1.0", + "domutils": "^3.2.2", "encoding-sniffer": "^0.2.0", - "htmlparser2": "^9.1.0", - "parse5": "^7.1.2", - "parse5-htmlparser2-tree-adapter": "^7.0.0", + "htmlparser2": "^10.0.0", + "parse5": "^7.3.0", + "parse5-htmlparser2-tree-adapter": "^7.1.0", "parse5-parser-stream": "^7.1.2", - "undici": "^6.19.5", + "undici": "^7.10.0", "whatwg-mimetype": "^4.0.0" }, "engines": { @@ -2842,6 +2859,16 @@ } } }, + "node_modules/cosmiconfig/node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -3042,9 +3069,9 @@ } }, "node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -3227,6 +3254,16 @@ "node": ">=8" } }, + "node_modules/dir-glob/node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -3350,9 +3387,9 @@ "license": "MIT" }, "node_modules/encoding-sniffer": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz", - "integrity": "sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz", + "integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==", "dev": true, "license": "MIT", "dependencies": { @@ -3446,9 +3483,9 @@ } }, "node_modules/es-abstract": { - "version": "1.23.9", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz", - "integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==", + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", + "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", "dev": true, "license": "MIT", "dependencies": { @@ -3456,18 +3493,18 @@ "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", - "call-bound": "^1.0.3", + "call-bound": "^1.0.4", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", + "es-object-atoms": "^1.1.1", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", - "get-intrinsic": "^1.2.7", - "get-proto": "^1.0.0", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", @@ -3479,21 +3516,24 @@ "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", "is-regex": "^1.2.1", + "is-set": "^2.0.3", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", - "is-weakref": "^1.1.0", + "is-weakref": "^1.1.1", "math-intrinsics": "^1.1.0", - "object-inspect": "^1.13.3", + "object-inspect": "^1.13.4", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", - "regexp.prototype.flags": "^1.5.3", + "regexp.prototype.flags": "^1.5.4", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", @@ -3502,7 +3542,7 @@ "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", - "which-typed-array": "^1.1.18" + "which-typed-array": "^1.1.19" }, "engines": { "node": ">= 0.4" @@ -3713,9 +3753,9 @@ } }, "node_modules/eslint-compat-utils/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, "license": "ISC", "bin": { @@ -3953,9 +3993,9 @@ } }, "node_modules/eslint-plugin-n/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, "license": "ISC", "bin": { @@ -4261,9 +4301,9 @@ } }, "node_modules/fastq": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.0.tgz", - "integrity": "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -4342,9 +4382,9 @@ "peer": true }, "node_modules/focus-trap": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.6.4.tgz", - "integrity": "sha512-xx560wGBk7seZ6y933idtjJQc1l+ck+pI3sKvhKozdBV1dRZoKhkW5xoCaFv9tQiX5RH1xfSxjuNu6g+lmN/gw==", + "version": "7.6.5", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.6.5.tgz", + "integrity": "sha512-7Ke1jyybbbPZyZXFxEftUtxFGLMpE2n6A+z//m4CRDlj0hW+o3iYSmh8nFlYMurOiJVDmJRilUQtJr08KfIxlg==", "dev": true, "license": "MIT", "dependencies": { @@ -4389,14 +4429,15 @@ } }, "node_modules/form-data": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", - "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz", + "integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", "mime-types": "^2.1.12" }, "engines": { @@ -4466,29 +4507,26 @@ } }, "node_modules/fuse.js": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.1.0.tgz", - "integrity": "sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==", - "dev": true, + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-6.6.2.tgz", + "integrity": "sha512-cJaJkxCCxC8qIIcPBF9yGxY0W/tVZS3uEISDxhYIdtk8OL93pe+6Zj7LjCqVV4dzbqcriOZ+kQ/NE4RXZHsIGA==", "license": "Apache-2.0", - "optional": true, - "peer": true, "engines": { "node": ">=10" } }, "node_modules/get-intrinsic": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz", - "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", + "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "get-proto": "^1.0.0", + "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", @@ -4533,9 +4571,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz", - "integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", + "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4682,26 +4720,14 @@ } }, "node_modules/globby/node_modules/ignore": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.3.tgz", - "integrity": "sha512-bAH5jbK/F3T3Jls4I0SO1hmPR0dKU0a7+SY6n1yzRtG54FLO8d6w/nxLFX2Nb7dBu6cCWXPaAME6cYqFUMmuCA==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "license": "MIT", "engines": { "node": ">= 4" } }, - "node_modules/globby/node_modules/path-type": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", - "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/globjoin": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", @@ -4991,9 +5017,9 @@ } }, "node_modules/htmlparser2": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", - "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.0.0.tgz", + "integrity": "sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==", "dev": true, "funding": [ "https://github.com/fb55/htmlparser2?sponsor=1", @@ -5006,8 +5032,21 @@ "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", - "domutils": "^3.1.0", - "entities": "^4.5.0" + "domutils": "^3.2.1", + "entities": "^6.0.0" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, "node_modules/http-proxy-agent": { @@ -5060,9 +5099,9 @@ } }, "node_modules/immutable": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.0.3.tgz", - "integrity": "sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz", + "integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==", "dev": true, "license": "MIT" }, @@ -5403,6 +5442,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -6135,9 +6187,9 @@ "license": "MIT" }, "node_modules/micromark-util-types": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.1.tgz", - "integrity": "sha512-534m2WhVTddrcKVepwmVEVnUAmtrx9bfIjNoQHRqfnvdaHQiFytEhJoTgpWJvDEXCO5gLTQh3wYC1PgOJA4NSQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", "dev": true, "funding": [ { @@ -6253,9 +6305,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "funding": [ { "type": "github", @@ -6302,9 +6354,9 @@ } }, "node_modules/normalize-package-data/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, "license": "ISC", "bin": { @@ -6338,9 +6390,9 @@ } }, "node_modules/nwsapi": { - "version": "2.2.16", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.16.tgz", - "integrity": "sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==", + "version": "2.2.20", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.20.tgz", + "integrity": "sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==", "license": "MIT" }, "node_modules/object-inspect": { @@ -6563,12 +6615,12 @@ } }, "node_modules/parse5": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", - "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", "license": "MIT", "dependencies": { - "entities": "^4.5.0" + "entities": "^6.0.0" }, "funding": { "url": "https://github.com/inikulin/parse5?sponsor=1" @@ -6601,6 +6653,18 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, + "node_modules/parse5/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -6639,13 +6703,15 @@ "license": "MIT" }, "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", + "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", "license": "MIT", "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/perfect-debounce": { @@ -6684,9 +6750,9 @@ } }, "node_modules/postcss": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", - "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "version": "8.5.5", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.5.tgz", + "integrity": "sha512-d/jtm+rdNT8tpXuHY5MMtcbJFBkhXE6593XVR9UoGCH8jSFGci7jGvMGH5RYd5PBJW+00NZQt6gf7CbagJCrhg==", "funding": [ { "type": "opencollective", @@ -6703,7 +6769,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.8", + "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -6837,9 +6903,9 @@ "license": "MIT" }, "node_modules/preact": { - "version": "10.26.2", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.26.2.tgz", - "integrity": "sha512-0gNmv4qpS9HaN3+40CLBAnKe0ZfyE4ZWo5xKlC1rVrr0ckkEvJvAQqKaHANdFKsGstoxrY4AItZ7kZSGVoVjgg==", + "version": "10.26.9", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.26.9.tgz", + "integrity": "sha512-SSjF9vcnF27mJK1XyFMNJzFd5u3pQiATFqoaDy03XuN00u4ziveVVEGt5RKJrDR8MHE/wJo9Nnad56RLzS2RMA==", "dev": true, "license": "MIT", "funding": { @@ -6858,9 +6924,9 @@ } }, "node_modules/property-information": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.0.0.tgz", - "integrity": "sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", "dev": true, "license": "MIT", "funding": { @@ -7171,9 +7237,9 @@ } }, "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -7205,13 +7271,13 @@ } }, "node_modules/rollup": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.8.tgz", - "integrity": "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.43.0.tgz", + "integrity": "sha512-wdN2Kd3Twh8MAEOEJZsuxuLKCsBEo4PVNLK6tQWAn10VhsVewQLzcucMgLolRlhFybGxfclbPeEYBaP6RvUFGg==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.6" + "@types/estree": "1.0.7" }, "bin": { "rollup": "dist/bin/rollup" @@ -7221,25 +7287,26 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.34.8", - "@rollup/rollup-android-arm64": "4.34.8", - "@rollup/rollup-darwin-arm64": "4.34.8", - "@rollup/rollup-darwin-x64": "4.34.8", - "@rollup/rollup-freebsd-arm64": "4.34.8", - "@rollup/rollup-freebsd-x64": "4.34.8", - "@rollup/rollup-linux-arm-gnueabihf": "4.34.8", - "@rollup/rollup-linux-arm-musleabihf": "4.34.8", - "@rollup/rollup-linux-arm64-gnu": "4.34.8", - "@rollup/rollup-linux-arm64-musl": "4.34.8", - "@rollup/rollup-linux-loongarch64-gnu": "4.34.8", - "@rollup/rollup-linux-powerpc64le-gnu": "4.34.8", - "@rollup/rollup-linux-riscv64-gnu": "4.34.8", - "@rollup/rollup-linux-s390x-gnu": "4.34.8", - "@rollup/rollup-linux-x64-gnu": "4.34.8", - "@rollup/rollup-linux-x64-musl": "4.34.8", - "@rollup/rollup-win32-arm64-msvc": "4.34.8", - "@rollup/rollup-win32-ia32-msvc": "4.34.8", - "@rollup/rollup-win32-x64-msvc": "4.34.8", + "@rollup/rollup-android-arm-eabi": "4.43.0", + "@rollup/rollup-android-arm64": "4.43.0", + "@rollup/rollup-darwin-arm64": "4.43.0", + "@rollup/rollup-darwin-x64": "4.43.0", + "@rollup/rollup-freebsd-arm64": "4.43.0", + "@rollup/rollup-freebsd-x64": "4.43.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.43.0", + "@rollup/rollup-linux-arm-musleabihf": "4.43.0", + "@rollup/rollup-linux-arm64-gnu": "4.43.0", + "@rollup/rollup-linux-arm64-musl": "4.43.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.43.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.43.0", + "@rollup/rollup-linux-riscv64-gnu": "4.43.0", + "@rollup/rollup-linux-riscv64-musl": "4.43.0", + "@rollup/rollup-linux-s390x-gnu": "4.43.0", + "@rollup/rollup-linux-x64-gnu": "4.43.0", + "@rollup/rollup-linux-x64-musl": "4.43.0", + "@rollup/rollup-win32-arm64-msvc": "4.43.0", + "@rollup/rollup-win32-ia32-msvc": "4.43.0", + "@rollup/rollup-win32-x64-msvc": "4.43.0", "fsevents": "~2.3.2" } }, @@ -7334,9 +7401,9 @@ "license": "MIT" }, "node_modules/sass": { - "version": "1.85.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.85.0.tgz", - "integrity": "sha512-3ToiC1xZ1Y8aU7+CkgCI/tqyuPXEmYGJXO7H4uqp0xkLXUqp88rQQ4j1HmP37xSJLbCJPaIiv+cT1y+grssrww==", + "version": "1.89.2", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.89.2.tgz", + "integrity": "sha512-xCmtksBKd/jdJ9Bt9p7nPKiuqrlBMBuuGkQlkhZjjQk3Ty48lv93k5Dq6OPkKt4XwxDJ7tvlfrTa1MPA9bf+QA==", "dev": true, "license": "MIT", "dependencies": { @@ -7788,6 +7855,20 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "license": "BSD-3-Clause" }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -8061,9 +8142,9 @@ } }, "node_modules/stylelint-declaration-strict-value": { - "version": "1.10.7", - "resolved": "https://registry.npmjs.org/stylelint-declaration-strict-value/-/stylelint-declaration-strict-value-1.10.7.tgz", - "integrity": "sha512-FlMvc3uoQtMcItW3Zh8lHJ7oN2KGns3vZDCaTZoGFRiRIjImQoxO+6gAeRf+Dgi0nXFICIPq9xxFsMi8zuYUsg==", + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/stylelint-declaration-strict-value/-/stylelint-declaration-strict-value-1.10.11.tgz", + "integrity": "sha512-oVQvhZlFZAiDz9r2BPFZLtTGm1A2JVhdKObKAJoTjFfR4F/NpApC4bMBTxf4sZS76Na3njYKVOaAaKSZ4+FU+g==", "dev": true, "license": "MIT", "engines": { @@ -8321,9 +8402,9 @@ "dev": true }, "node_modules/swagger-ui-dist": { - "version": "5.22.0", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.22.0.tgz", - "integrity": "sha512-8YlCSxiyb8uPFa7qoB1lRHYr1PBbT1NuV9RvQdFFPFPudRBTPf9coU5jl02KhzvrtmTEw4jXRgb0kg8pJvVuWQ==", + "version": "5.24.1", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.24.1.tgz", + "integrity": "sha512-ITeWc7CCAfK53u8jnV39UNqStQZjSt+bVYtJHsOEL3vVj/WV9/8HmsF8Ej4oD8r+Xk1HpWyeW/t59r1QNeAcUQ==", "license": "Apache-2.0", "dependencies": { "@scarf/scarf": "=1.4.0" @@ -8597,19 +8678,19 @@ } }, "node_modules/undici": { - "version": "6.21.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.1.tgz", - "integrity": "sha512-q/1rj5D0/zayJB2FraXdaWxbhWiNKDvu8naDT2dl1yTlvJp4BLtOcp2a5BvgGNQpYYJzau7tf1WgKv3b+7mqpQ==", + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.10.0.tgz", + "integrity": "sha512-u5otvFBOBZvmdjWLVW+5DAc9Nkq8f24g0O9oY7qw2JVIF1VocIFoyz9JFkuVOS2j41AufeO0xnlweJ2RLT8nGw==", "dev": true, "license": "MIT", "engines": { - "node": ">=18.17" + "node": ">=20.18.1" } }, "node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", + "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", "dev": true, "license": "MIT", "optional": true, @@ -8975,21 +9056,21 @@ } }, "node_modules/vitepress/node_modules/@types/node": { - "version": "22.13.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.4.tgz", - "integrity": "sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==", + "version": "24.0.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.1.tgz", + "integrity": "sha512-MX4Zioh39chHlDJbKmEgydJDS3tspMP/lnQC67G3SWsTnb9NeYVWOjkxpOSy4oMfPs4StcWHwBrvUb4ybfnuaw==", "dev": true, "license": "MIT", "optional": true, "peer": true, "dependencies": { - "undici-types": "~6.20.0" + "undici-types": "~7.8.0" } }, "node_modules/vitepress/node_modules/@vitejs/plugin-vue": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.1.tgz", - "integrity": "sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", + "integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==", "dev": true, "license": "MIT", "engines": { @@ -9001,9 +9082,9 @@ } }, "node_modules/vitepress/node_modules/vite": { - "version": "5.4.14", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.14.tgz", - "integrity": "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==", + "version": "5.4.19", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz", + "integrity": "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==", "dev": true, "license": "MIT", "dependencies": { @@ -9061,16 +9142,16 @@ } }, "node_modules/vue": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.13.tgz", - "integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==", + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.16.tgz", + "integrity": "sha512-rjOV2ecxMd5SiAmof2xzh2WxntRcigkX/He4YFJ6WdRvVUrbt6DxC1Iujh10XLl8xCDRDtGKMeO3D+pRQ1PP9w==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.13", - "@vue/compiler-sfc": "3.5.13", - "@vue/runtime-dom": "3.5.13", - "@vue/server-renderer": "3.5.13", - "@vue/shared": "3.5.13" + "@vue/compiler-dom": "3.5.16", + "@vue/compiler-sfc": "3.5.16", + "@vue/runtime-dom": "3.5.16", + "@vue/server-renderer": "3.5.16", + "@vue/shared": "3.5.16" }, "peerDependencies": { "typescript": "*" @@ -9091,15 +9172,6 @@ "nanoid": "^4.0.0" } }, - "node_modules/vue-command-palette/node_modules/fuse.js": { - "version": "6.6.2", - "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-6.6.2.tgz", - "integrity": "sha512-cJaJkxCCxC8qIIcPBF9yGxY0W/tVZS3uEISDxhYIdtk8OL93pe+6Zj7LjCqVV4dzbqcriOZ+kQ/NE4RXZHsIGA==", - "license": "Apache-2.0", - "engines": { - "node": ">=10" - } - }, "node_modules/vue-command-palette/node_modules/nanoid": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.2.tgz", @@ -9128,9 +9200,9 @@ } }, "node_modules/vue-router": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.5.0.tgz", - "integrity": "sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==", + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.5.1.tgz", + "integrity": "sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw==", "license": "MIT", "dependencies": { "@vue/devtools-api": "^6.6.4" @@ -9289,16 +9361,17 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.18.tgz", - "integrity": "sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==", + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", "dev": true, "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "for-each": "^0.3.3", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" }, @@ -9341,9 +9414,9 @@ } }, "node_modules/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz", + "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==", "license": "MIT", "engines": { "node": ">=10.0.0" From 566aecb514dd592886d58c01f3c9473cf4a9ecd7 Mon Sep 17 00:00:00 2001 From: Robert Means Date: Fri, 13 Jun 2025 15:38:10 -0400 Subject: [PATCH 5/8] Modal dark styling --- docs/.vitepress/theme/styles/swagger.styl | 249 ++++++++++++++++++++++ 1 file changed, 249 insertions(+) diff --git a/docs/.vitepress/theme/styles/swagger.styl b/docs/.vitepress/theme/styles/swagger.styl index a23bd247..a549b973 100644 --- a/docs/.vitepress/theme/styles/swagger.styl +++ b/docs/.vitepress/theme/styles/swagger.styl @@ -687,4 +687,253 @@ html.dark #swagger-ui .model-deprecated-warning { html.dark #swagger-ui span > span.model .brace-close { padding: 0 0 0 10px; color: #e2e8f0; +} + +/* === AUTHORIZATION MODAL === */ +html.dark #swagger-ui .dialog-ux { + /* Modal backdrop */ +} + +html.dark #swagger-ui .dialog-ux .backdrop-ux { + background: rgba(15, 15, 35, 0.85); +} + +html.dark #swagger-ui .dialog-ux .modal-ux { + background-color: #1a1a2e; + border: 1px solid #2a2a40; + box-shadow: 0 10px 30px 0 rgba(0, 0, 0, 0.5); +} + +/* Modal header */ +html.dark #swagger-ui .dialog-ux .modal-ux-header { + border-bottom: 1px solid #2a2a40; +} + +html.dark #swagger-ui .dialog-ux .modal-ux-header h3 { + color: #ffffff; +} + +html.dark #swagger-ui .dialog-ux .modal-ux-header .close-modal { + color: #94a3b8; + background: none; + border: none; + cursor: pointer; + font-size: 18px; + transition: color 0.2s ease; +} + +html.dark #swagger-ui .dialog-ux .modal-ux-header .close-modal:hover { + color: #ffffff; +} + +/* Close button SVG styling */ +html.dark #swagger-ui .dialog-ux .modal-ux-header .close-modal svg { + fill: currentColor; + width: 16px; + height: 16px; +} + +/* Modal content */ +html.dark #swagger-ui .dialog-ux .modal-ux-content { + color: #e2e8f0; +} + +html.dark #swagger-ui .dialog-ux .modal-ux-content p { + color: #e2e8f0; +} + +html.dark #swagger-ui .dialog-ux .modal-ux-content h4 { + color: #ffffff; +} + +/* Auth containers */ +html.dark #swagger-ui .auth-container { + border-bottom: 1px solid #2a2a40; +} + +html.dark #swagger-ui .auth-container:last-of-type { + border-bottom: none; +} + +html.dark #swagger-ui .auth-container h4 { + color: #ffffff; +} + +/* Auth form inputs */ +html.dark #swagger-ui .auth-container input[type="text"], +html.dark #swagger-ui .auth-container input[type="password"] { + background-color: #16213e; + color: #e2e8f0; + border: 1px solid #2a2a40; + border-radius: 4px; + padding: 8px 12px; +} + +html.dark #swagger-ui .auth-container input[type="text"]:focus, +html.dark #swagger-ui .auth-container input[type="password"]:focus { + border-color: #60a5fa; + box-shadow: 0 0 0 2px rgba(96, 165, 250, 0.2); + outline: none; +} + +html.dark #swagger-ui .auth-container input[type="text"]::placeholder, +html.dark #swagger-ui .auth-container input[type="password"]::placeholder { + color: #64748b; +} + +/* Error messages */ +html.dark #swagger-ui .auth-container .errors { + background-color: rgba(239, 68, 68, 0.1); + color: #fca5a5; + border: 1px solid rgba(239, 68, 68, 0.3); +} + +html.dark #swagger-ui .auth-container .errors b { + color: #ef4444; +} + +/* Scopes section */ +html.dark #swagger-ui .scopes h2 { + color: #ffffff; +} + +html.dark #swagger-ui .scopes h2 a { + color: #60a5fa; +} + +html.dark #swagger-ui .scopes h2 a:hover { + color: #93c5fd; +} + +/* Scope definitions */ +html.dark #swagger-ui .scope-def { + color: #e2e8f0; +} + +/* Checkboxes for scopes */ +html.dark #swagger-ui .auth-container input[type="checkbox"] { + appearance: none; + width: 16px; + height: 16px; + border: 2px solid #2a2a40; + border-radius: 3px; + background-color: #16213e; + position: relative; + cursor: pointer; + margin-right: 8px; +} + +html.dark #swagger-ui .auth-container input[type="checkbox"]:checked { + background-color: #60a5fa; + border-color: #60a5fa; +} + +html.dark #swagger-ui .auth-container input[type="checkbox"]:checked::after { + content: "✓"; + position: absolute; + top: -2px; + left: 2px; + color: #ffffff; + font-size: 12px; + font-weight: bold; +} + +html.dark #swagger-ui .auth-container input[type="checkbox"]:focus { + box-shadow: 0 0 0 2px rgba(96, 165, 250, 0.2); + outline: none; +} + +/* Auth button wrapper */ +html.dark #swagger-ui .auth-btn-wrapper { + border-top: 1px solid #2a2a40; + padding: 15px 20px; + background-color: rgba(26, 26, 46, 0.5); +} + +/* Auth buttons */ +html.dark #swagger-ui .auth-btn-wrapper .btn, +html.dark #swagger-ui .btn.authorize, +html.dark #swagger-ui .btn[type="submit"] { + background-color: #60a5fa !important; + color: #ffffff !important; + border: none !important; + border-radius: 4px; + padding: 8px 16px; + cursor: pointer; + font-weight: 500; + transition: background-color 0.2s ease; + text-shadow: none !important; +} + +html.dark #swagger-ui .auth-btn-wrapper .btn:hover, +html.dark #swagger-ui .btn.authorize:hover, +html.dark #swagger-ui .btn[type="submit"]:hover { + background-color: #3b82f6 !important; + color: #ffffff !important; +} + +html.dark #swagger-ui .auth-btn-wrapper .btn-done, +html.dark #swagger-ui .btn-done { + background-color: #34d399 !important; + color: #ffffff !important; +} + +html.dark #swagger-ui .auth-btn-wrapper .btn-done:hover, +html.dark #swagger-ui .btn-done:hover { + background-color: #10b981 !important; + color: #ffffff !important; +} + +/* Cancel/secondary buttons */ +html.dark #swagger-ui .auth-btn-wrapper .btn.cancel { + background-color: transparent; + color: #94a3b8; + border: 1px solid #2a2a40; +} + +html.dark #swagger-ui .auth-btn-wrapper .btn.cancel:hover { + background-color: rgba(42, 42, 64, 0.3); + color: #ffffff; +} + +/* Labels and form text */ +html.dark #swagger-ui .auth-container label { + color: #e2e8f0; + font-weight: 500; + display: block; + margin-bottom: 4px; +} + +/* Auth wrapper (the authorize button in topbar) */ +html.dark #swagger-ui .auth-wrapper .authorize { + color: #94a3b8; +} + +html.dark #swagger-ui .auth-wrapper .authorize:hover { + color: #60a5fa; +} + +/* Small text and descriptions */ +html.dark #swagger-ui .auth-container small, +html.dark #swagger-ui .auth-container .description { + color: #94a3b8; + font-size: 11px; +} + +/* OAuth flow information */ +html.dark #swagger-ui .auth-container .flow { + color: #94a3b8; + font-style: italic; +} + +/* Token display area */ +html.dark #swagger-ui .auth-container .token { + background-color: #16213e; + border: 1px solid #2a2a40; + border-radius: 4px; + padding: 8px; + font-family: monospace; + font-size: 12px; + color: #fbbf24; + word-break: break-all; } \ No newline at end of file From b7bc56b2a63196e2557eb54d162b447c399d3aaf Mon Sep 17 00:00:00 2001 From: Robert Means Date: Wed, 25 Jun 2025 15:33:43 -0400 Subject: [PATCH 6/8] Link update --- docs/reference/api/sandbox.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/docs/reference/api/sandbox.md b/docs/reference/api/sandbox.md index b1214735..3e1776b9 100644 --- a/docs/reference/api/sandbox.md +++ b/docs/reference/api/sandbox.md @@ -21,16 +21,12 @@ description: Interactive OpenAPI documentation for ApostropheCMS REST API ## About This Reference -This interactive documentation is generated from our [OpenAPI specification](/openapi.yaml). You can: +This interactive documentation is generated from our [OpenAPI specification](/apostrophecms-openapi.yaml). You can: - **Test endpoints live**: Make real API calls to your locally running project (with authentication) - **View request/response examples**: See exactly what data to send and expect - **Understand schemas**: Explore all data models and field requirements - **Copy code samples**: Get ready-to-use code -## Need the Raw Specification? - -- [Download YAML format](/openapi.yaml) - For human reading and editing - ## Start learning about the ApostropheCMS API [Learn more about API authentication →](/reference/api/authentication) From 48c176c339cde4d33165d221dfc25975113bccb1 Mon Sep 17 00:00:00 2001 From: Robert Means Date: Fri, 5 Dec 2025 08:29:56 -0500 Subject: [PATCH 7/8] Add Swagger UI and OpenAPI file to docs --- .../.vitepress/components/AposApiExplorer.vue | 5 +- docs/images/swagger-login-route.png | Bin 0 -> 29341 bytes docs/images/swagger-user-endpoint.png | Bin 0 -> 23807 bytes docs/public/apostrophecms-openapi.yaml | 11387 +++++++++++----- docs/reference/api/sandbox.md | 152 +- package-lock.json | 47 +- package.json | 2 +- 7 files changed, 8312 insertions(+), 3281 deletions(-) create mode 100644 docs/images/swagger-login-route.png create mode 100644 docs/images/swagger-user-endpoint.png diff --git a/docs/.vitepress/components/AposApiExplorer.vue b/docs/.vitepress/components/AposApiExplorer.vue index 85511426..253ba72d 100644 --- a/docs/.vitepress/components/AposApiExplorer.vue +++ b/docs/.vitepress/components/AposApiExplorer.vue @@ -6,8 +6,9 @@ import { onMounted } from 'vue' onMounted(async () => { - const SwaggerUI = (await import('swagger-ui-dist/swagger-ui-bundle.js')).default - + const SwaggerUI = (await import('swagger-ui-dist/swagger-ui-es-bundle.js')).default + await import('swagger-ui-dist/swagger-ui.css') + SwaggerUI({ dom_id: '#swagger-ui', url: '/apostrophecms-openapi.yaml', diff --git a/docs/images/swagger-login-route.png b/docs/images/swagger-login-route.png new file mode 100644 index 0000000000000000000000000000000000000000..cc2258c71a7e7cfc3a5210c71909484a21c3b96d GIT binary patch literal 29341 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

s!Z)R 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.20.0" + notes: | + Spec versioning follows semver independently of CMS releases. + isCore: true + + # Used by the expander to control localization flags & nicer names. + pieceTypes: + standard: + - '@apostrophecms/image' + - '@apostrophecms/file' + - '@apostrophecms/image-tag' + - '@apostrophecms/file-tag' + - '@apostrophecms/submitted-draft' + + nonLocalizable: + - '@apostrophecms/user' + - '@apostrophecms/global' + + marketingTags: + '@apostrophecms/image': Media + '@apostrophecms/file': Media + '@apostrophecms/image-tag': Media + '@apostrophecms/file-tag': Media + '@apostrophecms/user': Users + '@apostrophecms/global': Global Content + '@apostrophecms/submitted-draft': Submitted Draft + + # 👇 fallback for any piece not listed above + defaultPieceMarketingTag: Custom + + # adds the module name as a second tag + includeTechnicalTag: true + +security: + # adds session authentication as the default + - SessionAuth: [] + servers: - url: http://localhost:3000/api/v1 description: Development server - url: https://your-site.com/api/v1 description: Production server (not for online use) +tags: + - name: Authentication + description: 🚀 Login, logout, and session management for API access - start here! + - name: Pages + description: 🚀 Essential for headless sites - page structure, content, and navigation + - name: Users + description: Built-in user management and authentication + - name: Global Content + description: Site-wide settings and content that appears across pages + - name: Submitted Drafts + description: Draft submission workflow and review queue management + - name: Media + description: File uploads, image management, and media organization + - name: Attachments + description: File upload utilities and image processing + - name: Internationalization + description: Multi-language support and locale management + - name: Custom + description: Project-defined piece types (your own content models) + +x-tagGroups: + - name: Start Here + tags: [Authentication] + - name: Content & Media + tags: [Pages, Global Content, Submitted Draft, Media, Attachments] + - name: People + tags: [Users] + - name: Internationalization + tags: [Internationalization] + - name: Custom + tags: [Custom] components: securitySchemes: @@ -58,7 +135,7 @@ components: in: query name: apikey description: | - API key for server-to-server communication. + **Server-to-server authentication** - API key for server-to-server communication. Use as query parameter: ?apikey=your-api-key-here Configure in app.js: @@ -76,12 +153,9 @@ components: type: http scheme: bearer description: | - ⚠️ **Security Note:** Only use test credentials in this online sandbox. - Real credentials should never be entered in public documentation. - Bearer token authentication (recommended for API clients). - **Step 1:** Use the `POST /@apostrophecms/login/login` endpoint below with: + **Step 1:** Close this dialog box and generate a bearer token using the `POST /@apostrophecms/login/login` endpoint below with: ```json { "username": "your-username", @@ -93,18 +167,19 @@ components: Example: if response is `{"token": "abc123"}`, paste only `abc123` The token will be sent as: Authorization: Bearer {your-token} + **Step 3:** Reopen this dialog and paste the token value into the value field. + SessionAuth: type: apiKey in: cookie name: project-shortname.sid description: | - ⚠️ **For testing after download only:** Change "project-shortname" in the `SessionAuth` to your actual - ApostropheCMS shortname (e.g., "myapp.sid"). + ⚠️ **For testing after download only:** Change "project-shortname" in the `SessionAuth` to your actual ApostropheCMS shortname (e.g., "myapp.sid"). 💡 This authentication won't work when testing in the online ApostropheCMS sandbox. However, you can use the login route to set a cookie you can examine in your browser DevTools. It will be named `project-shortname.sid`. - **Step 1:** Use the `POST /@apostrophecms/login/login` endpoint below with: + **Step 1:** Close this dialog and use the `POST /@apostrophecms/login/login` endpoint below with: ```json { "username": "your-username", @@ -113,19 +188,20 @@ components: } ``` - **Step 2:** Copy the session cookie value from your browser's dev tools - and paste it into the "Value" field above. + **Step 2:** Copy the session cookie value from your browser's dev tools + and paste it into the "Value" field. parameters: Page: name: page in: query - description: Page number for pagination + description: Page number for pagination (1-based) required: false schema: type: integer minimum: 1 default: 1 + example: 2 PerPage: name: perPage @@ -137,6 +213,7 @@ components: minimum: 1 maximum: 100 default: 10 + example: 25 Search: name: search @@ -145,6 +222,7 @@ components: required: false schema: type: string + example: "headless cms" Autocomplete: name: autocomplete @@ -153,688 +231,1607 @@ components: required: false schema: type: string + example: "apost" AposMode: name: aposMode in: query - description: Request draft or published version + description: Request draft or published version of content required: false schema: type: string enum: [draft, published] default: published + example: "published" AposLocale: name: aposLocale in: query - description: Locale for internationalization + description: Locale for internationalization (e.g., 'en', 'fr', 'es') required: false schema: type: string example: "fr" + ToLocale: + name: toLocale + in: path + required: true + description: Target locale code (e.g., en:us:published) + schema: + type: string + pattern: '^[a-z]{2}(-[A-Z]{2})?$' + example: en + RenderAreas: name: render-areas in: query - description: Render area content as HTML instead of returning widget data + description: 💡 Render widget areas as HTML instead of returning raw widget data - useful for hybrid architectures required: false schema: type: boolean default: false + example: true - PageId: + DocumentId: name: _id in: path required: true - description: Page document ID (can include mode and locale, e.g., id:en:published) + description: Computed document ID (can optionally include mode and locale, e.g., id:en:published) schema: type: string + pattern: '^\S+$' example: "ckitdo5oq004pu69kr6oxo6fr:en:published" + AposDocId: + name: aposDocId + in: path + required: true + description: ApostropheCMS document identifier + schema: + type: string + pattern: '^[a-zA-Z0-9]+$' + example: "ckitdo5oq004pu69kr6oxo6fr" + + ImageDocId: + name: imageId + in: path + required: true + description: ApostropheCMS document identifier for an image + schema: + type: string + pattern: '^[a-zA-Z0-9]+$' + example: "ck9x8v7w2000001l6h8q9d5f0" + AllPages: name: all in: query - description: Include entire page tree regardless of depth + description: Return all pages the requester can see (system/orphan pages included). Use with caution for large sites. Default is 0. schema: - type: string - enum: ["1"] - example: "1" + type: integer + enum: [0,1] + default: 0 + example: 1 FlatResponse: name: flat in: query - description: Return pages in flat array instead of tree structure + description: 💡 Return pages in flat array instead of tree structure - easier for some use cases. Default is 0 (nested). schema: - type: string - enum: ["1"] - example: "1" + type: integer + enum: [0,1] + default: 0 + example: 1 ChildrenParam: name: children in: query - description: Include children array in response + description: Include children array in response (set to 'false' to exclude). Default is true. schema: - type: string - enum: ["false"] - example: "false" + type: boolean + default: true + example: false schemas: - PageTreeResponse: + _Overview_Fields: type: object - description: Home page with nested children structure - properties: - _id: - type: string - description: Unique document identifier - example: "ckhdscx5900054z9k88uqs16w" - orphan: - type: boolean - description: Whether page is excluded from navigation - example: false - visibility: - type: string - enum: [public, loginRequired, private] - description: Page visibility setting - example: "public" - type: - type: string - description: Page type identifier - example: "@apostrophecms/home-page" - title: - type: string - description: Page title - example: "Home Page" - slug: - type: string - description: URL slug for the page - example: "/" - rank: - type: integer - description: Order among sibling pages - example: 0 - level: - type: integer - description: Page tree depth level - example: 0 - path: - type: string - description: Ancestor path of page IDs - example: "ckhdscx5900054z9k88uqs16w" - _url: - type: string - format: uri - description: Complete page URL - example: "http://localhost:3000/" - _ancestors: - type: array - items: - $ref: '#/components/schemas/PageSummary' - description: Array of ancestor pages - _children: - type: array - items: - $ref: '#/components/schemas/PageTreeResponse' - description: Array of child pages - createdAt: - type: string - format: date-time - description: ISO date of creation - updatedAt: - type: string - format: date-time - description: ISO date of last update - archived: - type: boolean - description: Whether page is archived - example: false - historicUrls: - type: array - items: - type: string - description: Previous URLs that redirect to this page - metaType: - type: string - example: "doc" - titleSortified: - type: string - description: Sortable version of title - updatedBy: - $ref: '#/components/schemas/User' - _edit: - type: boolean - description: Edit permission flag - - FlatPageResponse: + description: | + # Field Types (editor-facing) + + - `StringField` — basic text + - `IntegerField`, `FloatField` — numbers + - `SelectField`, `RadioField`, `CheckboxesField` — choices + - `AreaField`, `ArrayField`, `ObjectField` + - `AttachmentField`, `RelationshipField`, `RelationshipReverseField` + + 👉 See also: **FieldDefinition** (discriminator: `type`). + externalDocs: + description: ApostropheCMS Field Guide + url: https://docs.apostrophecms.org/reference/field-types/ + title: _Overview_Fields + _Overview_Primitives: type: object - properties: - results: - type: array - items: - allOf: - - $ref: '#/components/schemas/PageTreeResponse' - - type: object - properties: - _children: - type: array - items: - type: string - description: Array of child page IDs (in flat response) - _ancestors: - type: array - items: - type: string - description: Array of ancestor page IDs (in flat response) + description: | + # Content Primitives (payload-level) - PageSummary: - type: object - description: Abbreviated page information for ancestors/references - properties: - _id: - type: string - title: - type: string - slug: - type: string - type: - type: string - _url: - type: string - format: uri - level: - type: integer - rank: - type: integer + These are the “data atoms” for requests and responses. - PageCreateRequest: - type: object - required: - - _targetId - - _position - - title - properties: - _targetId: - type: string - description: ID of target page for positioning (_home and _archive are convenience values) - example: "ckhdscx5900054z9k88uqs16w" - _position: - oneOf: - - type: string - enum: [before, after, firstChild, lastChild] - - type: integer - minimum: 0 - description: Position relative to target (string values) or child index (number) - example: "firstChild" - _copyingId: - type: string - description: Optional ID of existing page to copy properties from - title: - type: string - description: Page title - example: "My New Page" - slug: - type: string - description: URL slug (auto-generated if not provided) - example: "/my-new-page" - type: - type: string - description: Page type - example: "default-page" - visibility: - type: string - enum: [public, loginRequired, private] - default: public - # Add other fields based on your page types + - `AposString`, `AposSlug`, `AposUrl`, `AposEmail` + - `AposDateTime`, `AposDate`, `AposTime` + - Arrays: `AposStringArray`, `AposIntegerArray`, etc. - PageUpdateRequest: + 👉 Defined under **AposPrimitives**. + title: _Overview_Primitives + _Overview_Advanced: type: object - properties: - _targetId: - type: string - description: ID of target page for repositioning (required if moving page) - _position: - oneOf: - - type: string - enum: [before, after, firstChild, lastChild] - - type: integer - minimum: 0 - description: New position (required if moving page) - title: - type: string - description: Updated page title - slug: - type: string - description: Updated URL slug - visibility: - type: string - enum: [public, loginRequired, private] - updatedBy: - $ref: '#/components/schemas/User' - - Area: + description: | + # Advanced / Internal + + Used by OpenAPI for schema defs: + - `UiCondition` (for `if`/`requiredIf`) + - `OperatorObject` (query operators) + - `AreaOptions`, `ArrayOptions`, and other config helpers + title: _Overview_Advanced + AreaField: + allOf: + - $ref: '#/components/schemas/BaseField' + - type: object + additionalProperties: false + properties: + type: + type: string + enum: + - area + description: Apostrophe field type id. + options: + $ref: '#/components/schemas/AreaOptions' + if: + $ref: '#/components/schemas/UiCondition' + requiredIf: + $ref: '#/components/schemas/UiCondition' + required: + - type + - label + - options + examples: + - type: area + label: Main content + options: + max: 3 + expanded: true + widgets: + '@apostrophecms/image': {} + '@apostrophecms/rich-text': + toolbar: + - bold + - italic + '@apostrophecms/video': {} + '@apostrophecms/html': {} + groups: + basics: + label: Basic Content + columns: 3 + widgets: + '@apostrophecms/rich-text': + toolbar: + - bold + '@apostrophecms/image': {} + embeds: + label: Embeds + columns: 2 + widgets: + '@apostrophecms/video': {} + '@apostrophecms/html': {} + title: AreaField + AreaOptions: type: object - description: Content area containing widgets + additionalProperties: false properties: - _id: - type: string - example: "ckj0k0dy7000i2a68s1z8v4ky" # Add examples - metaType: - type: string - enum: [area] # Make it an enum for precision - example: "area" - items: - type: array - description: "Array of widgets within this area" # Add description - items: - $ref: '#/components/schemas/Widget' - _edit: + widgets: + description: | + Allowed widget types for this area. Keys are widget module names (e.g., "@apostrophecms/rich-text"). Values are per-widget options that apply *only* in this area. + type: object + additionalProperties: + type: object + groups: + description: | + Organize widgets into groups for the expanded preview menu. + Each group has a label, optional columns (1–4, default 3), and its own widgets map (same shape as `widgets`). + type: object + additionalProperties: + $ref: '#/components/schemas/AreaWidgetGroup' + max: + type: integer + description: Maximum number of widgets allowed in this area. + expanded: type: boolean - description: "Whether area is in edit mode" # Document this important property - _docId: - type: string - example: "ckj0k2i45001c7u9kky3tftx2" - - Widget: + description: Use the expanded preview menu UX. + required: + - widgets + title: AreaOptions + AreaWidgetGroup: type: object - description: Content widget within an area + additionalProperties: false properties: - _id: - type: string - metaType: - type: string - enum: [widget] - type: - type: string - example: "@apostrophecms/rich-text" - _edit: - type: boolean - _docId: - type: string - # Rich text widget specific properties - content: + label: type: string - description: "HTML content for rich text widgets (filtered based on widget configuration)" - example: "

Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.

" - import: + columns: + type: integer + minimum: 1 + maximum: 4 + description: Number of widget previews per row (default 3). + widgets: type: object - description: "Import configuration for external content (used during creation/update)" - properties: - baseUrl: - type: string - format: uri - description: "Base URL for resolving relative image URLs" - example: "https://myoldsite.com" - html: - type: string - description: "HTML content to import (images will be automatically imported)" - example: "

Here is some text.

\n" - additionalProperties: true - - # Array Field + additionalProperties: + type: object + required: + - label + - widgets + title: AreaWidgetGroup ArrayField: - type: array - description: "Array field containing structured data items" - items: - type: object + allOf: + - $ref: '#/components/schemas/BaseField' + - type: object + additionalProperties: false + description: A repeatable list of objects, each with its own field schema. properties: - _id: + type: type: string - description: "Automatically generated ID for each array item" - example: "ckj0k15x4001h2a68staejzpj" - additionalProperties: true - example: - _id: "ckj0k15x4001h2a68staejzpj" - label: "The first one" - count: 27 - - # Attachment Field - AttachmentField: - type: object - description: "File attachment with metadata and URLs" - properties: - _id: - type: string - example: "ckhdsopzr0005rt9kn49eyzb5" - crop: - type: string - nullable: true - description: "Crop settings for images" - group: - type: string - description: "File group classification" - example: "images" - createdAt: - type: string - format: date-time - example: "2020-11-11T19:27:11.782Z" - name: - type: string - description: "Original filename without extension" - example: "double-rainbow" - title: - type: string - description: "Display title for the attachment" - example: "double rainbow" - extension: - type: string - description: "File extension" - example: "jpg" - type: - type: string - enum: [attachment] - docIds: - type: array - items: + enum: + - array + description: Apostrophe field type id. + fields: + $ref: '#/components/schemas/Fieldset' + min: + type: integer + description: Minimum number of items (inclusive). + max: + type: integer + description: Maximum number of items (inclusive). + titleField: type: string - description: "Documents that reference this attachment" - archivedDocIds: - type: array + description: Field name in each item used as the item label in the UI. + if: + $ref: '#/components/schemas/UiCondition' + requiredIf: + $ref: '#/components/schemas/UiCondition' + required: + - type + - label + - fields + examples: + - type: array + label: Tasks + min: 0 + max: 50 + titleField: title items: + type: object + properties: + title: + type: string + priority: + type: string + fields: + add: + title: + type: string + label: Task Title + priority: + type: select + label: Priority + choices: + - label: Low + value: low + - label: High + value: high + title: ArrayField + AttachmentField: + allOf: + - $ref: '#/components/schemas/BaseField' + - type: object + additionalProperties: false + description: | + Lets editors upload a single file (image, PDF, etc.). + Use an ArrayField of AttachmentField if you need multiple files. + properties: + type: type: string - length: - type: integer - description: "File size in bytes" - example: 644584 - md5: - type: string - description: "MD5 hash of the original file" - example: "f41217031f11e8483ee81e20782f51be" - width: - type: integer - description: "Image width in pixels" - example: 2560 - height: - type: integer - description: "Image height in pixels" - example: 1922 - landscape: - type: boolean - description: "Whether image is in landscape orientation" - used: - type: boolean - description: "Whether attachment is currently used" - utilized: - type: boolean - description: "Whether attachment is utilized" - archived: - type: boolean - description: "Whether attachment is archived" - _urls: - type: object - description: "Available image sizes and URLs (for images only)" - properties: - max: - type: string - format: uri - example: "https://example.net/uploads/attachments/ckhdsopzr0005rt9kn49eyzb5-double-rainbow.max.jpg" - full: - type: string - format: uri - example: "https://example.net/uploads/attachments/ckhdsopzr0005rt9kn49eyzb5-double-rainbow.full.jpg" - two-thirds: - type: string - format: uri - example: "https://example.net/uploads/attachments/ckhdsopzr0005rt9kn49eyzb5-double-rainbow.two-thirds.jpg" - one-half: - type: string - format: uri - example: "https://example.net/uploads/attachments/ckhdsopzr0005rt9kn49eyzb5-double-rainbow.one-half.jpg" - one-third: - type: string - format: uri - example: "https://example.net/uploads/attachments/ckhdsopzr0005rt9kn49eyzb5-double-rainbow.one-third.jpg" - one-sixth: - type: string - format: uri - example: "https://example.net/uploads/attachments/ckhdsopzr0005rt9kn49eyzb5-double-rainbow.one-sixth.jpg" - original: - type: string - format: uri - example: "https://example.net/uploads/attachments/ckhdsopzr0005rt9kn49eyzb5-double-rainbow.jpg" - additionalProperties: - type: string - format: uri - _url: - type: string - format: uri - description: "Single URL for non-image files" - - # Relationship Field - RelationshipField: - type: array - description: "Array of related documents" - items: - type: object + enum: + - attachment + description: Apostrophe field type id. + accept: + oneOf: + - type: string + description: HTML "accept" string (e.g., "image/*,.pdf"). Use to limitby MIME type and/or extension. + - type: array + items: + type: string + description: List of MIME types and/or extensions (e.g., ["image/*", + ".pdf"]). + maxSize: + type: integer + description: Optional max file size in bytes (documentation-only hint). + if: + $ref: '#/components/schemas/UiCondition' + requiredIf: + $ref: '#/components/schemas/UiCondition' + required: + - type + - label + examples: + - type: attachment + label: Resume (PDF) + accept: + - .pdf + required: true + - type: attachment + label: Hero Image + accept: image/* + title: AttachmentField + BooleanField: + allOf: + - $ref: '#/components/schemas/BaseField' + - type: object + additionalProperties: false properties: - _id: + type: type: string - example: "ckitdkktu002bu69krdkdu2pj" - archived: - type: boolean - disabled: + enum: + - boolean + description: Apostrophe field type id. + def: type: boolean + description: Default value shown in the editor UI. + toggle: + oneOf: + - type: boolean + description: | + If true, use the alternate "toggle" UI. + Labels default to the field label and standard true/false text. + - type: object + additionalProperties: false + description: Configure custom labels for the toggle UI. + properties: + 'true': + type: string + description: Label to display when value is true. + 'false': + type: string + description: Label to display when value is false. + required: + - type + - label + examples: + - type: boolean + label: Is this a special item? + def: false + - type: boolean + label: Show related articles? + toggle: + 'true': Show related articles + 'false': Hide related articles + title: BooleanField + CheckboxesField: + allOf: + - $ref: '#/components/schemas/BaseField' + - type: object + additionalProperties: false + properties: type: type: string - description: "Document type" - example: "@apostrophecms/user" - title: + enum: + - checkboxes + description: Apostrophe field type id. + def: + type: array + items: + oneOf: + - type: string + - type: number + - type: boolean + description: Default selected values. + choices: + oneOf: + - type: array + description: Static choices for the checkboxes. + items: + $ref: '#/components/schemas/SelectChoice' + - type: string + description: Method name that provides choices dynamically. + following: + oneOf: + - type: string + - type: array + items: + type: string + description: Populate dynamically based on other fields (supports `<` parent prefixes). + followingIgnore: + oneOf: + - type: boolean + - type: array + items: + type: string + description: Ignore some or all followed fields when generating values. + if: + $ref: '#/components/schemas/UiCondition' + requiredIf: + $ref: '#/components/schemas/UiCondition' + required: + - type + - label + - choices + examples: + - type: checkboxes + label: Tags + choices: + - label: News + value: news + - label: Blog + value: blog + - label: Events + value: events + def: + - news + - events + title: CheckboxesField + ColorField: + allOf: + - $ref: '#/components/schemas/BaseField' + - type: object + additionalProperties: false + properties: + type: type: string - example: "Alexander Hamilton" - slug: + enum: + - color + description: Apostrophe field type id. + def: type: string - example: "user-alexander-hamilton" - metaType: + pattern: ^#(?:[0-9a-fA-F]{3}){1,2}$ + description: Default hex color (e.g. "#ff0000"). + if: + $ref: '#/components/schemas/UiCondition' + requiredIf: + $ref: '#/components/schemas/UiCondition' + required: + - type + - label + examples: + - type: color + label: Theme Color + def: '#336699' + title: ColorField + DateField: + allOf: + - $ref: '#/components/schemas/BaseField' + - $ref: '#/components/schemas/DateBoundaryOptions' + - type: object + additionalProperties: false + properties: + type: type: string - enum: [doc] - createdAt: + enum: + - date + description: Apostrophe field type id. + def: type: string - format: date-time - updatedAt: + format: date + description: Default date shown in the editor UI (YYYY-MM-DD). + if: + $ref: '#/components/schemas/UiCondition' + requiredIf: + $ref: '#/components/schemas/UiCondition' + required: + - type + - label + examples: + - type: date + label: Publish Date + def: '2025-01-01' + min: '2020-01-01' + max: '2030-12-31' + - type: date + label: Event Date + if: + status: + $eq: scheduled + title: DateField + DateAndTimeField: + allOf: + - $ref: '#/components/schemas/BaseField' + - $ref: '#/components/schemas/DateTimeBoundaryOptions' + - type: object + additionalProperties: false + properties: + type: + type: string + enum: + - dateAndTime + description: Apostrophe field type id. + def: type: string format: date-time - updatedBy: - type: object - properties: - _id: + description: Default timestamp in RFC 3339 format (e.g., 2025-08-29T13:00:00Z). + if: + $ref: '#/components/schemas/UiCondition' + requiredIf: + $ref: '#/components/schemas/UiCondition' + required: + - type + - label + examples: + - type: dateAndTime + label: Starts At + def: '2025-08-29T13:00:00Z' + min: '2024-01-01T00:00:00Z' + max: '2026-12-31T23:59:59Z' + - type: dateAndTime + label: Reminder At + requiredIf: + remindersEnabled: true + title: DateAndTimeField + EmailField: + allOf: + - $ref: '#/components/schemas/BaseField' + - type: object + additionalProperties: false + properties: + type: + type: string + enum: + - email + description: Apostrophe field type id. + def: + type: string + format: email + description: Default email address shown in the editor UI. + pattern: + type: string + description: Optional regex for stricter validation (in addition to HTML5 + email validation). + autocomplete: + type: string + description: Value for the HTML autocomplete attribute. Common values are + "email" or "off". + if: + $ref: '#/components/schemas/UiCondition' + requiredIf: + $ref: '#/components/schemas/UiCondition' + required: + - type + - label + examples: + - type: email + label: Contact Email + def: info@example.com + - type: email + label: Support Email + autocomplete: email + requiredIf: + supportEnabled: true + title: EmailField + FloatField: + allOf: + - $ref: '#/components/schemas/BaseField' + - $ref: '#/components/schemas/NumericRangeOptions' + - type: object + additionalProperties: false + properties: + type: + type: string + enum: + - float + format: + type: string + enum: + - float + description: OpenAPI hint for tooling; always "float". + def: + type: number + format: float + description: Default decimal value. + examples: + - type: float + label: Price (USD) + help: Enter a decimal price. + def: 0.0 + min: 0 + max: 99999.99 + required: true + title: FloatField + IntegerField: + allOf: + - $ref: '#/components/schemas/BaseField' + - $ref: '#/components/schemas/NumericRangeOptions' + - type: object + additionalProperties: false + properties: + type: + type: string + enum: + - integer + description: Apostrophe field type id. + def: + type: integer + description: Default integer value shown in the editor UI. + required: + - type + - label + examples: + - type: integer + label: Age + min: 0 + max: 120 + def: 18 + - type: integer + label: Estimated Hours + min: 1 + max: 999 + title: IntegerField + ObjectField: + allOf: + - $ref: '#/components/schemas/BaseField' + - type: object + additionalProperties: false + description: A nested object with its own field schema. + properties: + type: + type: string + enum: + - object + fields: + $ref: '#/components/schemas/Fieldset' + if: + $ref: '#/components/schemas/UiCondition' + requiredIf: + $ref: '#/components/schemas/UiCondition' + required: + - type + - label + - fields + title: ObjectField + OembedField: + allOf: + - $ref: '#/components/schemas/BaseField' + - type: object + additionalProperties: false + properties: + type: + type: string + enum: + - oembed + description: Apostrophe field type id. + if: + $ref: '#/components/schemas/UiCondition' + requiredIf: + $ref: '#/components/schemas/UiCondition' + required: + - type + - label + description: | + Lets editors paste a media URL from an oEmbed-compatible host. + The editor shows an immediate preview once a valid URL is entered. + Stored value is an object snapshot (url/title/thumbnail). + examples: + - type: oembed + label: Featured video + title: OembedField + PasswordField: + allOf: + - $ref: '#/components/schemas/BaseField' + - type: object + additionalProperties: false + properties: + type: + type: string + enum: + - password + description: Apostrophe field type id. + def: + type: string + description: Default password value (generally not used). + min: + type: integer + description: Minimum number of characters required. + max: + type: integer + description: Maximum number of characters allowed. + pattern: + type: string + description: Regex to enforce password rules (e.g., at least one number). + autocomplete: + type: string + description: HTML autocomplete attribute, usually "new-password" or "current-password". + if: + $ref: '#/components/schemas/UiCondition' + requiredIf: + $ref: '#/components/schemas/UiCondition' + required: + - type + - label + examples: + - type: password + label: Account Password + min: 8 + autocomplete: new-password + title: PasswordField + RadioField: + allOf: + - $ref: '#/components/schemas/BaseField' + - type: object + additionalProperties: false + properties: + type: + type: string + enum: + - radio + description: Apostrophe field type id. + def: + oneOf: + - type: string + - type: number + - type: boolean + description: Default selected value. + choices: + oneOf: + - type: array + description: Static choices to render as radio buttons. + items: + $ref: '#/components/schemas/SelectChoice' + - type: string + description: Method name that provides choices (e.g. "statusChoices"). + following: + oneOf: + - type: string + - type: array + items: type: string - firstName: + description: Populate dynamically based on other fields (supports `<` parent prefixes). + followingIgnore: + oneOf: + - type: boolean + - type: array + items: type: string - lastName: + description: Ignore some or all followed fields when generating values. + if: + $ref: '#/components/schemas/UiCondition' + requiredIf: + $ref: '#/components/schemas/UiCondition' + required: + - type + - label + - choices + examples: + - type: radio + label: Priority + choices: + - label: Low + value: low + - label: High + value: high + def: low + - type: radio + label: Status + choices: statusChoices + title: RadioField + RangeField: + allOf: + - $ref: '#/components/schemas/BaseField' + - $ref: '#/components/schemas/NumericRangeOptions' + - type: object + additionalProperties: false + properties: + type: + type: string + enum: + - range + description: Apostrophe field type id. + def: + type: number + description: Default slider value in the editor UI. + step: + type: number + description: Increment step for the slider. If omitted, defaults to 1. + min: + type: number + description: Minimum value for the slider. + max: + type: number + description: Maximum value for the slider. + if: + $ref: '#/components/schemas/UiCondition' + requiredIf: + $ref: '#/components/schemas/UiCondition' + required: + - type + - label + examples: + - type: range + label: Satisfaction + min: 1 + max: 10 + step: 1 + def: 5 + - type: range + label: Volume + min: 0 + max: 100 + step: 5 + def: 50 + title: RangeField + RelationshipField: + allOf: + - $ref: '#/components/schemas/BaseField' + - type: object + additionalProperties: false + description: | + Relate this document to one or more docs of another type (pieces/pages). + Use `max: 1` for a single-select join; omit `max` (or set >1) for multi-select. + properties: + type: + type: string + enum: + - relationship + description: Apostrophe field type id. + withType: + type: string + description: Module name of the related doc type (e.g., "article", "@apostrophecms/image"). + min: + type: integer + description: Minimum number of related docs required (inclusive). + max: + type: integer + description: Maximum number of related docs allowed (inclusive). + fields: + $ref: '#/components/schemas/Fieldset' + builders: + type: object + additionalProperties: true + description: | + Apostrophe cursor builders for the related query (e.g., {project: { title: 1 }, sort: { title: 1 } }). + if: + $ref: '#/components/schemas/UiCondition' + requiredIf: + $ref: '#/components/schemas/UiCondition' + required: + - type + - label + - withType + examples: + - type: relationship + label: Author + withType: person + max: 1 + builders: + project: + title: 1 + _url: 1 + - type: relationship + label: Related Articles + withType: article + min: 0 + max: 5 + fields: + add: + relationshipRole: + type: select + label: Role + choices: + - label: Primary + value: primary + - label: Secondary + value: secondary + builders: + project: + title: 1 + _url: 1 + sort: + title: 1 + title: RelationshipField + RelationshipReverseField: + allOf: + - $ref: '#/components/schemas/BaseField' + - type: object + additionalProperties: false + description: | + Read-only reverse side of a forward `relationship` field defined on another type. + Use this to show “referenced by” links without storing ids here. + properties: + type: + type: string + enum: + - relationshipReverse + description: Apostrophe field type id. + withType: + type: string + description: Module name that holds the forward relationship. + reverseOf: + type: string + description: | + Name of the forward relationship field on `withType` (e.g.,"_authors" on "article"). + builders: + type: object + additionalProperties: true + description: Cursor builders applied when populating the reverse join. + if: + $ref: '#/components/schemas/UiCondition' + requiredIf: + $ref: '#/components/schemas/UiCondition' + required: + - type + - label + - withType + - reverseOf + examples: + - type: relationshipReverse + label: Articles referencing this person + withType: article + reverseOf: _authors + builders: + project: + title: 1 + _url: 1 + title: RelationshipReverseField + SelectField: + allOf: + - $ref: '#/components/schemas/BaseField' + - type: object + additionalProperties: false + properties: + type: + type: string + enum: + - select + description: Apostrophe field type id. + def: + oneOf: + - type: string + - type: number + - type: boolean + - type: array + items: + oneOf: + - type: string + - type: number + - type: boolean + description: | + Default value. If `multiple: true`, this should be an array. + multiple: + type: boolean + description: Allow selecting multiple values (stores an array). + choices: + oneOf: + - type: array + description: Static choices for the select dropdown. + items: + $ref: '#/components/schemas/SelectChoice' + - type: string + description: | + Name of a method that returns choices (e.g. "sponsorNames"). + May be "module:method" to reference another module. + following: + oneOf: + - type: string + - type: array + items: type: string - username: + description: Populate dynamically based on other fields’ values (supports `<` parent prefixes). + followingIgnore: + oneOf: + - type: boolean + - type: array + items: type: string - titleSortified: + description: Ignore some or all followed fields when generating values. + required: + - type + - label + examples: + - type: select + label: Task Priority + choices: + - label: Low + value: low + - label: Medium + value: medium + - label: High + value: high + - label: Critical + value: critical + def: medium + - type: select + label: Tags + multiple: true + choices: + - label: News + value: news + - label: Blog + value: blog + - label: Events + value: events + def: + - news + - events + - type: select + label: Sponsor + choices: sponsorNames + following: + - Welcome to our website!

+ _id: + type: string + example: widget-id-123 + seoFields: + type: object + description: SEO metadata for the page + properties: + metaDescription: + type: string + description: Meta description for search engines + maxLength: 160 + example: Learn about our company, mission, and values + metaKeywords: + type: string + description: Meta keywords (legacy, rarely used) + example: about, company, mission + ogTitle: + type: string + description: Open Graph title for social sharing + example: About Our Company + ogDescription: + type: string + description: Open Graph description for social sharing + example: Discover our story and what drives us forward + ogImage: + type: object + description: Open Graph image for social sharing + properties: + _id: + type: string + example: image-id-456 + title: + type: string + example: Company Photo + attachment: + type: object + properties: + _id: + type: string + example: attachment-789 + name: + type: string + example: company-photo + extension: + type: string + example: jpg + _url: + type: string + example: /uploads/attachments/company-photo.jpg + _ancestors: + type: array + description: Array of ancestor page IDs in the page tree hierarchy + items: + type: string + example: + - root-page-id + _children: + type: array + description: Array of child pages (when requested with children parameter) + items: + $ref: '#/components/schemas/Page' + example: [] + _url: + type: string + description: Full URL to the page + example: https://example.com/about-us + format: uri + _edit: + type: boolean + description: Whether current user can edit this page + example: true + _publish: + type: boolean + description: Whether current user can publish this page + example: true + _publishedDoc: + allOf: + - $ref: '#/components/schemas/Page' + - description: Published version of the page (when viewing drafts) + _draftDoc: + allOf: + - $ref: '#/components/schemas/Page' + - description: Draft version of the page (when viewing published) + required: + - _id + - aposDocId + - type + - title + - slug + - path + - level + additionalProperties: true + example: + _id: ckhdscx5900054z9k88uqs16w:en:published + aposDocId: ckhdscx5900054z9k88uqs16w + aposLocale: en + aposMode: published + archived: false + createdAt: '2023-01-15T10:30:00.000Z' + updatedAt: '2024-12-18T14:20:00.000Z' + titleSortified: about us + slug: /about-us + path: /about-us + rank: 0 + level: 1 + orphan: false + parked: [] + visibility: public + type: '@apostrophecms/page' + title: About Us + main: + metaType: area + items: + - metaType: widget + type: '@apostrophecms/rich-text' + aposPlaceholder: false + content:

Welcome to our company! We've been serving customers since 2020.

+ _id: widget-123 + seoFields: + metaDescription: Learn about our company, mission, and values + ogTitle: About Our Company + ogDescription: Discover our story and what drives us forward + _ancestors: + - root-page-id + _children: [] + _url: https://example.com/about-us + _edit: true + _publish: true + title: Page + User: + type: object + description: | + Built-in user piece type for account management. + + **Base Properties**: Inherited from @apostrophecms/piece-type + **User-Specific Properties**: title, username, email, role, disabled + + 💡 Developers can add custom fields to the user piece type in their project configuration. + properties: + _id: + type: string + description: Unique identifier + example: clx1234567890abcdef + title: + type: string + description: User's display name + example: John Developer + username: + type: string + description: Login username (must be unique) + example: johndeveloper + email: + type: string + format: email + description: User's email address + example: john@example.com + role: + type: string + description: User role - determines permissions + enum: + - guest + - contributor + - editor + - admin + example: editor + disabled: + type: boolean + description: Whether the user account is disabled + default: false + archived: + type: boolean + description: Whether the user is archived + default: false + visibility: + type: string + description: Visibility setting + enum: + - public + - loginRequired + default: loginRequired + type: + type: string + example: '@apostrophecms/user' + slug: + type: string + example: user-johndeveloper + createdAt: + type: string + format: date-time + description: Account creation date + updatedAt: + type: string + format: date-time + description: Last update date + title: User + Global: + type: object + description: | + 'Built-in global content piece type for site-wide settings. + + 💡 Developers can add custom fields to the global piece type in their project + configuration. + properties: + _id: + type: string + description: Unique identifier + example: global + title: + type: string + description: Default title field + readOnly: true + example: global + slug: + type: string + description: Default slug field + readOnly: true + example: global + type: + type: string + example: '@apostrophecms/global' + readOnly: true + additionalProperties: true + title: Global + GlobalPatch: + type: object + description: | + Allows for patching of costom user added fields. + It blocks the modification of the title, slu, and type fields. + properties: + title: + type: string + description: Default title field + readOnly: true + example: global + slug: + type: string + description: Default slug field + readOnly: true + example: global + type: + type: string + example: '@apostrophecms/global' + readOnly: true + additionalProperties: true + Attachment: + type: object + description: File attachment information from upload endpoint + properties: + _id: + type: string + description: Unique attachment identifier + example: ckj0akbxa003vp39kfbxgb8zg + _url: type: string description: URL to the original file - example: "https://example.net/uploads/attachments/ckj0akbxa003vp39kfbxgb8zg-blue-box.png" + example: https://example.net/uploads/attachments/ckj0akbxa003vp39kfbxgb8zg-blue-box.png _urls: type: object description: URLs for different image sizes (images only) @@ -843,22 +1840,22 @@ components: name: type: string description: Slugified filename - example: "blue-box" + example: blue-box title: type: string description: Sortified filename - example: "blue box" + example: blue box extension: type: string description: File extension - example: "png" + example: png type: type: string - example: "attachment" + example: attachment group: type: string description: File group type - example: "images" + example: images length: type: integer description: File size in bytes @@ -866,7 +1863,7 @@ components: md5: type: string description: MD5 checksum - example: "630eeaaecd0bdc07c4a82eeca4c07588" + example: 630eeaaecd0bdc07c4a82eeca4c07588 width: type: integer description: Image width in pixels (images only) @@ -897,32 +1894,34 @@ components: updatedAt: type: string format: date-time - + title: Attachment Image: type: object - description: Built-in image/media piece type + description: Built-in image/media piece type for managing photos and graphics properties: _id: type: string description: Unique identifier - example: "clx1234567890abcdef" + example: clx1234567890abcdef title: type: string description: Image title/alt text - example: "Hero banner image" + example: Hero banner image slug: type: string - example: "hero-banner-image" + example: hero-banner-image type: type: string - example: "@apostrophecms/image" + example: '@apostrophecms/image' archived: type: boolean default: false visibility: type: string - enum: ["public", "loginRequired"] - default: "public" + enum: + - public + - loginRequired + default: public attachment: type: object description: File attachment information @@ -931,17 +1930,17 @@ components: type: string name: type: string - example: "hero-banner" + example: hero-banner extension: type: string - example: "jpg" + example: jpg length: type: integer description: File size in bytes url: type: string description: Public URL to access the image - example: "/uploads/attachments/clx123/hero-banner.jpg" + example: /uploads/attachments/clx123/hero-banner.jpg credit: type: string description: Image credit or attribution @@ -956,32 +1955,35 @@ components: updatedAt: type: string format: date-time - - File: + title: Image + FileObject: type: object - description: Built-in file piece type for general file uploads (PDFs, documents, etc.) + description: Built-in file piece type for general file uploads (PDFs, documents, + etc.) properties: _id: type: string description: Unique identifier - example: "clx1234567890abcdef" + example: clx1234567890abcdef title: type: string description: File title/description - example: "Company Brochure" + example: Company Brochure slug: type: string - example: "company-brochure" + example: company-brochure type: type: string - example: "@apostrophecms/file" + example: '@apostrophecms/file' archived: type: boolean default: false visibility: type: string - enum: ["public", "loginRequired"] - default: "public" + enum: + - public + - loginRequired + default: public attachment: type: object description: File attachment information @@ -990,17 +1992,17 @@ components: type: string name: type: string - example: "company-brochure" + example: company-brochure extension: type: string - example: "pdf" + example: pdf length: type: integer description: File size in bytes url: type: string description: Public URL to access the file - example: "/uploads/attachments/clx123/company-brochure.pdf" + example: /uploads/attachments/clx123/company-brochure.pdf description: type: string description: File description @@ -1015,25 +2017,25 @@ components: updatedAt: type: string format: date-time - + title: File ImageTag: type: object description: Built-in image tag piece type for organizing images properties: _id: type: string - example: "clx1234567890abcdef" + example: clx1234567890abcdef title: type: string description: Tag name - example: "Hero Images" + example: Hero Images slug: type: string description: URL-friendly tag name - example: "hero-images" + example: hero-images type: type: string - example: "@apostrophecms/image-tag" + example: '@apostrophecms/image-tag' archived: type: boolean default: false @@ -1043,25 +2045,25 @@ components: updatedAt: type: string format: date-time - + title: ImageTag FileTag: type: object description: Built-in file tag piece type for organizing files properties: _id: type: string - example: "clx1234567890abcdef" + example: clx1234567890abcdef title: type: string description: Tag name - example: "Marketing Materials" + example: Marketing Materials slug: type: string description: URL-friendly tag name - example: "marketing-materials" + example: marketing-materials type: type: string - example: "@apostrophecms/file-tag" + example: '@apostrophecms/file-tag' archived: type: boolean default: false @@ -1071,118 +2073,124 @@ components: updatedAt: type: string format: date-time - - Article: + title: FileTag + SubmittedDraft: type: object - description: Example custom piece type - blog article (requires custom configuration) properties: _id: type: string - description: Unique identifier - example: "clx1234567890abcdef" + description: Unique identifier for the submitted draft + example: clh123abc456def789 + type: + type: string + description: Document type identifier + example: '@apostrophecms/submitted-draft' title: type: string - description: Article title - example: "Getting Started with Headless CMS" + description: Title of the submitted draft + example: New Article Draft slug: type: string - description: URL-friendly version of title - example: "getting-started-headless-cms" - type: + description: URL-friendly version of the title + example: new-article-draft + content: type: string - example: "article" - archived: - type: boolean - default: false - visibility: + description: Content of the submitted draft + example: This is the draft content awaiting review. + author: type: string - enum: ["public", "loginRequired"] - default: "public" - body: - type: object - description: Rich text content area - properties: - metaType: - type: string - example: "area" - items: - type: array - items: - type: object - description: Content widgets (rich text, images, etc.) - publishedAt: + description: Author of the submitted draft + example: John Doe + authorId: type: string - format: date-time - description: Publication date - example: "2024-12-15T10:30:00.000Z" - tags: - type: array - items: - type: string - description: Article tags - example: ["cms", "headless", "tutorial"] - _author: - type: array - items: - $ref: '#/components/schemas/User' - description: Article authors (relationship field) - createdAt: + description: ID of the user who created the draft + example: clh456def789abc123 + submissionNotes: type: string - format: date-time - updatedAt: + description: Notes from the submitter about the draft + example: Please review for accuracy and tone. + priority: type: string - format: date-time - - Event: - type: object - description: Example custom piece type - calendar event (requires custom configuration) - properties: - _id: + enum: + - low + - normal + - high + - urgent + description: Priority level for review + example: normal + category: type: string - example: "clx1234567890abcdef" - title: + description: Category or type of content being submitted + example: blog-post + status: type: string - example: "ApostropheCMS Meetup" - slug: + enum: + - draft + - submitted + - under-review + - approved + - rejected + - published + description: Current status of the submitted draft + example: submitted + submittedAt: type: string - example: "apostrophecms-meetup" - type: + format: date-time + description: When the draft was submitted for review + example: '2024-03-15T10:30:00Z' + reviewedAt: type: string - example: "event" - archived: - type: boolean - default: false - visibility: + format: date-time + description: When the draft was last reviewed + example: '2024-03-16T14:20:00Z' + reviewedBy: type: string - enum: ["public", "loginRequired"] - default: "public" - description: - type: object - description: Rich text event description - startDate: + description: ID of the user who reviewed the draft + example: clh789ghi012jkl345 + reviewNotes: type: string - format: date-time - example: "2024-12-20T18:00:00.000Z" - endDate: + description: Notes from the reviewer + example: Approved with minor suggestions for improvement. + publishedAt: type: string format: date-time - example: "2024-12-20T20:00:00.000Z" - location: - type: string - example: "123 Developer Street, Tech City" - _image: - type: array - items: - $ref: '#/components/schemas/Image' - description: Event images (relationship field) + description: When the draft was published (if applicable) + example: '2024-03-17T09:00:00Z' + archived: + type: boolean + description: Whether the submitted draft is archived + default: false createdAt: type: string format: date-time + description: When the submitted draft was created + example: '2024-03-15T09:15:00Z' updatedAt: type: string format: date-time - - # Generic piece response structure + description: When the submitted draft was last updated + example: '2024-03-15T10:30:00Z' + aposLocale: + type: string + description: Locale for this version of the content + example: en + aposMode: + type: string + enum: + - draft + - published + description: Content mode (draft or published) + example: draft + required: + - _id + - type + - title + - content + - author + - status + - createdAt + - updatedAt + title: SubmittedDraft PieceResponse: type: object properties: @@ -1195,10 +2203,10 @@ components: error: type: string description: Error message if success is false - - # API Response schemas + title: PieceResponse PaginatedResponse: type: object + description: Standard response format for list endpoints properties: success: type: boolean @@ -1219,12 +2227,12 @@ components: total: type: integer description: Total number of items across all pages - + title: PaginatedResponse CreatePieceRequest: type: object description: Generic structure for creating any piece type required: - - title + - title properties: title: type: string @@ -1234,105 +2242,152 @@ components: description: URL slug (auto-generated from title if not provided) visibility: type: string - enum: ["public", "loginRequired"] + enum: + - public + - loginRequired description: Visibility setting - default: "public" + default: public archived: type: boolean description: Whether the piece is archived default: false - - Error: + title: CreatePieceRequest + ApiError: type: object properties: - error: + status: + type: integer + description: HTTP status code, e.g., 401 + code: type: string - description: Error message + description: Application error code (optional) message: type: string - description: Detailed error message - + description: Human-readable error message + details: + type: object + additionalProperties: true + description: Extra context about the error + required: + - message + title: Error LocalesResponse: type: object - description: "Object containing all configured locales" + description: Object containing all configured locales additionalProperties: type: object properties: label: type: string - description: "Human-readable locale name" - example: "English" + description: Human-readable locale name + example: English _edit: type: boolean - description: "Whether current user can edit content in this locale" + description: Whether current user can edit content in this locale example: true example: en: - label: "English" + label: English _edit: true fr: - label: "French" + label: French _edit: false - - # i18n Request Schemas + title: LocalesResponse LocaleRequest: type: object required: - - locale + - locale properties: locale: type: string - description: "Target locale code" - example: "fr" + description: Target locale code + example: fr contextDocId: type: string - description: "Optional document ID for the path" - example: "cloydg3ka0005qcls5vmg8sb9" + description: Optional document ID for the path + example: cloydg3ka0005qcls5vmg8sb9 clipboard: type: string - description: "Optional clipboard content for cross-domain situations" - example: "exampleClipboardContent" - + description: Optional clipboard content for cross-domain situations + example: exampleClipboardContent + title: LocaleRequest + PageLocaleResult: + type: object + properties: + _id: + type: string + description: | + Document ID with locale and mode (format: docId:locale:mode) + example: "s9gjqtw1ok7wxvewdu78xnes:en:published" + aposLocale: + type: string + description: | + Locale identifier with mode (format: locale:mode) + example: "en:published" + required: + - _id + - aposLocale + PageLocalesResponse: + type: object + properties: + results: + type: array + items: + $ref: '#/components/schemas/PageLocaleResult' + required: + - results SameHostnameResponse: type: object + additionalProperties: false + required: + - redirectTo properties: redirectTo: type: string - description: "Path to redirect to within same hostname" - example: "/fr/page-slug" - + description: Path to redirect to within same hostname + pattern: ^/(?!/).* + example: /fr/page-slug + title: SameHostnameResponse DifferentHostnameResponse: type: object + additionalProperties: false + required: + - redirectTo properties: redirectTo: type: string format: uri - description: "Full URL to redirect to with cross-domain session token" - example: "https://fr.example.com/french-example-page?aposCrossDomainSessionToken=generated_token" - + description: Full URL to redirect to with cross-domain session token + pattern: ^[A-Za-z][A-Za-z0-9+.-]*:// + example: https://fr.example.com/french-example-page?aposCrossDomainSessionToken=generated_token + title: DifferentHostnameResponse ExistInLocaleRequest: type: object required: - - ids - - locale - - mode + - ids + - locale + - mode properties: ids: type: array items: type: string - description: "Array of document IDs to check" - example: ["cloydg3ka0005qcls5vmg8sb9", "cloydg3ka0005qcls5vmg8sb8"] + description: Array of document IDs to check + example: + - cloydg3ka0005qcls5vmg8sb9 + - cloydg3ka0005qcls5vmg8sb8 locale: type: string - description: "Locale to check documents in" - example: "fr" + description: Locale to check documents in + example: fr mode: type: string - enum: [draft, published] - description: "Mode to check documents in" - example: "published" - + enum: + - draft + - published + description: Mode to check documents in + example: published + title: ExistInLocaleRequest ExistInLocaleResponse: type: object properties: @@ -1340,90 +2395,4603 @@ components: type: array items: type: string - description: "Array of document IDs in the original locale and mode" - example: ["cloydg3ka0005qcls5vmg8sb9:en:published", "cloydg3ka0005qcls5vmg8sb8:en:published"] + description: Array of document IDs in the original locale and mode + example: + - cloydg3ka0005qcls5vmg8sb9:en:published + - cloydg3ka0005qcls5vmg8sb8:en:published newLocaleIds: type: array items: type: string - description: "Array of document IDs in the new locale" - example: ["cloydg3ka0005qcls5vmg8sb9:fr:published", "cloydg3ka0005qcls5vmg8sb8:fr:published"] + description: Array of document IDs in the new locale + example: + - cloydg3ka0005qcls5vmg8sb9:fr:published + - cloydg3ka0005qcls5vmg8sb8:fr:published aposDocIds: type: array items: type: string - description: "Array of aposDocId values for the documents" - example: ["cloydg3ka0005qcls5vmg8sb9", "cloydg3ka0005qcls5vmg8sb8"] - - responses: - BadRequest: - description: Bad request - invalid input parameters - content: - application/json: - schema: - type: object - properties: - error: - type: string - example: "Invalid request parameters" - message: - type: string - example: "The request could not be processed due to invalid input" - - Unauthorized: - description: Authentication required - content: - application/json: - schema: - type: object - properties: - error: - type: string - example: "Unauthorized" - message: + description: Array of aposDocId values for the documents + example: + - cloydg3ka0005qcls5vmg8sb9 + - cloydg3ka0005qcls5vmg8sb8 + title: ExistInLocaleResponse + PageTreeResponse: + type: object + description: Complete page data with nested children structure - perfect for building + navigation + properties: + _id: + type: string + description: Unique document identifier + example: ckhdscx5900054z9k88uqs16w + orphan: + type: boolean + description: Whether page is excluded from navigation menus + example: false + visibility: + type: string + enum: + - public + - loginRequired + - private + description: Page visibility setting - controls who can view this page + example: public + type: + type: string + description: Page type identifier (configured in your project) + example: '@apostrophecms/home-page' + title: + type: string + description: Page title - used for navigation and SEO + example: Home Page + slug: + type: string + description: URL slug for the page + example: / + rank: + type: integer + description: Order among sibling pages (for navigation sorting) + example: 0 + level: + type: integer + description: Page tree depth level (0 = home page) + example: 0 + path: + type: string + description: Ancestor path of page IDs + example: ckhdscx5900054z9k88uqs16w + _url: + type: string + format: uri + description: Complete page URL - use this for links + example: http://localhost:3000/ + _ancestors: + type: array + items: + $ref: '#/components/schemas/PageSummary' + description: Array of ancestor pages (for breadcrumbs) + _children: + type: array + items: + $ref: '#/components/schemas/PageTreeResponse' + description: Array of child pages (nested structure) + createdAt: + type: string + format: date-time + description: ISO date of creation + updatedAt: + type: string + format: date-time + description: ISO date of last update + archived: + type: boolean + description: Whether page is archived (hidden from normal views) + example: false + historicUrls: + type: array + items: + type: string + description: Previous URLs that redirect to this page (SEO preservation) + metaType: + type: string + example: doc + titleSortified: + type: string + description: Sortable version of title + updatedBy: + $ref: '#/components/schemas/User' + _edit: + type: boolean + description: Whether current user can edit this page + title: PageTreeResponse + FlatPageResponse: + type: object + description: Pages returned as flat array instead of tree structure + properties: + results: + type: array + items: + allOf: + - $ref: '#/components/schemas/PageTreeResponse' + - type: object + properties: + _children: + type: array + items: + type: string + description: Array of child page IDs (in flat response) + _ancestors: + type: array + items: + type: string + description: Array of ancestor page IDs (in flat response) + title: FlatPageResponse + PageSummary: + type: object + description: Abbreviated page information for ancestors/references + properties: + _id: + type: string + title: + type: string + slug: + type: string + type: + type: string + _url: + type: string + format: uri + level: + type: integer + rank: + type: integer + title: PageSummary + PageCreateRequest: + type: object + required: + - _targetId + - _position + - title + properties: + _targetId: + type: string + description: ID of target page for positioning (_home and _archive are convenience + values) + example: ckhdscx5900054z9k88uqs16w + _position: + oneOf: + - type: string + enum: + - before + - after + - firstChild + - lastChild + - type: integer + minimum: 0 + description: Position relative to target (string values) or child index (number) + example: firstChild + _copyingId: + type: string + description: Optional ID of existing page to copy properties from + title: + type: string + description: Page title + example: My New Page + slug: + type: string + description: URL slug (auto-generated if not provided) + example: /my-new-page + type: + type: string + description: Page type (must be configured in your project) + example: default-page + visibility: + type: string + enum: + - public + - loginRequired + - private + default: public + description: Who can view this page + title: PageCreateRequest + PageUpdateRequest: + type: object + properties: + _targetId: + type: string + description: ID of target page for repositioning (required if moving page) + _position: + oneOf: + - type: string + enum: + - before + - after + - firstChild + - lastChild + - type: integer + minimum: 0 + description: New position (required if moving page) + title: + type: string + description: Updated page title + slug: + type: string + description: Updated URL slug + visibility: + type: string + enum: + - public + - loginRequired + - private + description: Updated visibility setting + updatedBy: + $ref: '#/components/schemas/User' + title: PageUpdateRequest + Widget: + type: object + description: Content widget within an area - represents a piece of structured + content + properties: + _id: + type: string + metaType: + type: string + enum: + - widget + type: + type: string + description: Widget type (e.g., rich-text, image, custom widgets) + example: '@apostrophecms/rich-text' + _edit: + type: boolean + _docId: + type: string + content: + type: string + description: HTML content for rich text widgets (filtered based on widget + configuration) + example:

Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum + nibh, ut fermentum massa justo sit amet risus.

+ import: + type: object + description: Import configuration for external content (used during creation/update) + properties: + baseUrl: + type: string + format: uri + description: Base URL for resolving relative image URLs + example: https://myoldsite.com + html: + type: string + description: HTML content to import (images will be automatically imported) + example: '

Here is some text.

+ + ' + imageTags: + type: array + items: type: string - example: "Authentication is required to access this resource" + description: Array of existing @apostrophecms/image-tag piece _ids to + apply to imported images + example: + - tag-piece-id-1 + - tag-piece-id-2 + title: Widget + PageDotNotationUpdate: + type: object + description: Keys may use Apostrophe dot notation to target nested content. + propertyNames: + pattern: ^[a-zA-Z0-9_]+(?:\.[a-zA-Z0-9_]+|\.\d+)+$ + additionalProperties: + oneOf: + - type: string + - type: number + - type: boolean + - type: object + - type: array + items: {} + - type: 'null' + title: PageDotNotationUpdate + BaseField: + type: object + additionalProperties: false + properties: + type: + type: string + description: Apostrophe field type id (e.g., "float", "string", "boolean"). + label: + type: string + description: Human-readable label for editors. + help: + type: string + description: Short helper text shown in the UI. + htmlHelp: + type: string + description: Rich helper text (HTML allowed by Apostrophe). + def: + description: Default value for this field (type varies by field). + required: + type: boolean + description: If true, value must be provided. + readOnly: + type: boolean + description: If true, UI should render as read-only (Apostrophe option). + hidden: + type: boolean + description: If true, hide in editor UI. + if: + $ref: '#/components/schemas/UiCondition' + requiredIf: + $ref: '#/components/schemas/UiCondition' + required: + - type + - label + title: BaseField + UiCondition: + type: object + additionalProperties: false + description: | + 'Apostrophe conditional used by `if` and `requiredIf`. + Keys are field paths (including `<` parent access and dot notation) or method calls with `()`. + Values are either simple equality (primitive) or an operator object. Supports `$or` / `$and` groups. See OperatorObject. + properties: + $or: + type: array + description: Any condition group may pass. :contentReference[oaicite:1]{index=1} + items: + $ref: '#/components/schemas/UiCondition' + $and: + type: array + description: All condition groups must pass. (Redundant at the same level, + but useful when nested with `$or`.) :contentReference[oaicite:2]{index=2} + items: + $ref: '#/components/schemas/UiCondition' + patternProperties: + ^[A-Za-z_][\\w-]*(?:\\.(?:length|\\d+|[A-Za-z_][\\w-]*))*$: + $ref: '#/components/schemas/FieldPredicate' + ^<+[A-Za-z_][\\w-]*(?:\\.(?:length|\\d+|[A-Za-z_][\\w-]*))*$: + $ref: '#/components/schemas/FieldPredicate' + ^(?:[A-Za-z0-9_-]+:)?[A-Za-z0-9_-]+\\(\\)$: + $ref: '#/components/schemas/FieldPredicate' + examples: + - priority: + $in: + - high + - critical + estimatedHours: + $gte: 20 + assignee.length: + $gt: 0 + - $or: + - seenMovie: true + - featuredMovie(): true + title: UiCondition + FieldPredicate: + description: A simple equality (primitive) or an OperatorObject. :contentReference[oaicite:5]{index=5} + oneOf: + - type: string + - type: number + - type: boolean + - type: 'null' + - $ref: '#/components/schemas/OperatorObject' + title: FieldPredicate + OperatorObject: + type: object + additionalProperties: false + description: | + MongoDB-style operators supported by Apostrophe conditions. + Note: + `$eq` has special handling with arrays (see docs). + `$exists: true` means not null/undefined; empty string is truthy so use `$ne: ''''` or check `.length`. + properties: + $eq: {} + $ne: {} + $gt: + type: number + $gte: + type: number + $lt: + type: number + $lte: + type: number + $in: + type: array + items: {} + $nin: + type: array + items: {} + $exists: + type: boolean + example: + $in: + - high + - critical + title: OperatorObject + NumericRangeOptions: + type: object + additionalProperties: false + properties: + min: + type: number + description: Minimum allowed value (inclusive). + max: + type: number + description: Maximum allowed value (inclusive) + title: NumericRangeOptions + DateBoundaryOptions: + type: object + additionalProperties: false + properties: + min: + type: string + format: date + description: Minimum allowed date (inclusive), ISO-8601 (YYYY-MM-DD). + max: + type: string + format: date + description: Maximum allowed date (inclusive), ISO-8601 (YYYY-MM-DD). + title: DateBoundaryOptions + DateTimeBoundaryOptions: + type: object + additionalProperties: false + properties: + min: + type: string + format: date-time + description: Minimum allowed timestamp (inclusive), RFC 3339. + max: + type: string + format: date-time + description: Maximum allowed timestamp (inclusive), RFC 3339. + title: DateTimeBoundaryOptions + RelationshipEntry: + type: object + description: | + One relationship entry. Always includes the related document `_id`. + If you declared per-relationship `fields`, those values are stored alongside `_id` here. + properties: + _id: + type: string + description: Id of the related document. + required: + - _id + additionalProperties: true + title: RelationshipEntry + BulkOperationRequest: + type: object + properties: + _ids: + type: array + items: + type: string + description: Array of document IDs to operate on + example: ["doc1:en:draft", "doc2:en:published"] + required: + - _ids + BulkOperationResponse: + type: object + properties: + success: + type: boolean + modified: + type: integer + description: Number of documents affected + errors: + type: array + items: + type: string + Fieldset: + type: object + additionalProperties: false + properties: + add: + type: object + additionalProperties: + $ref: '#/components/schemas/FieldDefinition' + required: + - add + title: Fieldset + FieldDefinition: + oneOf: + - $ref: '#/components/schemas/BooleanField' + - $ref: '#/components/schemas/StringField' + - $ref: '#/components/schemas/IntegerField' + - $ref: '#/components/schemas/FloatField' + - $ref: '#/components/schemas/SelectField' + - $ref: '#/components/schemas/RadioField' + - $ref: '#/components/schemas/CheckboxesField' + - $ref: '#/components/schemas/PasswordField' + - $ref: '#/components/schemas/ColorField' + - $ref: '#/components/schemas/DateField' + - $ref: '#/components/schemas/DateAndTimeField' + - $ref: '#/components/schemas/TimeField' + - $ref: '#/components/schemas/EmailField' + - $ref: '#/components/schemas/UrlField' + - $ref: '#/components/schemas/SlugField' + - $ref: '#/components/schemas/OembedField' + - $ref: '#/components/schemas/RangeField' + - $ref: '#/components/schemas/ObjectField' + - $ref: '#/components/schemas/ArrayField' + - $ref: '#/components/schemas/AreaField' + - $ref: '#/components/schemas/AttachmentField' + - $ref: '#/components/schemas/RelationshipField' + - $ref: '#/components/schemas/RelationshipReverseField' + discriminator: + propertyName: type + mapping: + boolean: '#/components/schemas/BooleanField' + string: '#/components/schemas/StringField' + integer: '#/components/schemas/IntegerField' + float: '#/components/schemas/FloatField' + select: '#/components/schemas/SelectField' + radio: '#/components/schemas/RadioField' + checkboxes: '#/components/schemas/CheckboxesField' + password: '#/components/schemas/PasswordField' + color: '#/components/schemas/ColorField' + date: '#/components/schemas/DateField' + dateAndTime: '#/components/schemas/DateAndTimeField' + time: '#/components/schemas/TimeField' + email: '#/components/schemas/EmailField' + url: '#/components/schemas/UrlField' + slug: '#/components/schemas/SlugField' + oembed: '#/components/schemas/OembedField' + range: '#/components/schemas/RangeField' + object: '#/components/schemas/ObjectField' + array: '#/components/schemas/ArrayField' + area: '#/components/schemas/AreaField' + attachment: '#/components/schemas/AttachmentField' + relationship: '#/components/schemas/RelationshipField' + relationshipReverse: '#/components/schemas/RelationshipReverseField' + title: FieldDefinition + AposPrimitives: + $id: https://example.com/apostrophe/primitives + $schema: https://json-schema.org/draft/2020-12/schema + description: | + Reusable primitive data shapes for ApostropheCMS document payloads. + Use these in content models; keep field-definition objects separate. + $defs: + AposString: + type: string + AposStringArray: + type: array + items: + $ref: '#/components/schemas/AposPrimitives/$defs/AposString' + AposSlug: + type: string + pattern: ^[a-z0-9][a-z0-9-]*$ + description: Slug string stored in the document, usually lowercase and URL-safe (e.g. "my-article", "blog/my-custom-page"). + AposEmail: + type: string + format: email + description: A valid email address per RFC 5322, as stored in documents and returned via the API. + AposURI: + type: string + format: uri + description: | + A valid absolute URL (RFC 3986). + Usually stored with protocol, e.g., "https://example.com". + AposPassword: + type: string + description: Password string as entered. Apostrophe typically hashes thisbefore storage; API usage depends on context. + AposDateTime: + type: string + format: date-time + description: ISO-8601 calendar date (YYYY-MM-DD). + AposDate: + type: string + format: date + description: RFC 3339 timestamp (e.g., 2025-08-29T13:00:00Z). + AposTime: + type: string + pattern: ^(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d$ + description: Time string stored in documents, always in HH:MM:SS (24-hour). + AposInteger: + type: integer + AposIntegerArray: + type: array + items: + $ref: '#/components/schemas/AposPrimitives/$defs/AposInteger' + AposFloat: + type: number + AposFloatArray: + type: array + items: + $ref: '#/components/schemas/AposPrimitives/$defs/AposFloat' + AposRange: + type: number + description: Stored numeric value selected via the slider (integer or float, depending on configuration). + AposBoolean: + type: boolean + AposBooleanArray: + type: array + items: + $ref: '#/components/schemas/AposPrimitives/$defs/AposBoolean' + AposRadio: + oneOf: + - type: string + - type: number + - type: boolean + description: The stored value for a radio field (one of the choice values). + AposCheckboxes: + type: array + items: + oneOf: + - type: string + - type: number + - type: boolean + description: The stored values for a checkboxes field. Each item is one of the configured choice values. + AposOembed: + type: object + additionalProperties: false + properties: + url: + type: string + format: uri + description: Original media URL saved by the editor. + title: + type: string + description: Title snapshot from the oEmbed response at save time. + thumbnail: + type: string + format: uri + description: Thumbnail URL snapshot from the oEmbed response at save time. + required: + - url + description: | + Data stored on the document: a snapshot of the oEmbed resource. + Fetch full embed HTML at runtime via GET `/api/v1/@apostrophecms/oembed/query?url=`. + AposArea: + type: object + additionalProperties: false + properties: + items: + type: array + items: + $ref: '#/components/schemas/Widget' + required: + - items + description: | + The value saved on the doc: an object with an `items` array of widgets. + # --- Data value (what’s stored on the doc) --- + AposAttachment: + type: object + description: | + Attachment metadata saved on the document. + Extra fields maybe present depending on project config and file type (e.g., image dimensions). + additionalProperties: true + properties: + _id: + type: string + description: Internal id of the uploaded file. + name: + type: string + description: Basename without extension. + extension: + type: string + description: File extension (e.g., "pdf", "png"). + mimeType: + type: string + description: MIME type (e.g., "application/pdf", "image/png"). + group: + type: string + description: Broad file group (e.g., "images", "office", "video", "audio", + "generic"). + size: + type: integer + description: File size in bytes. + width: + type: integer + description: Image width in pixels (if applicable). + height: + type: integer + description: Image height in pixels (if applicable). + required: + - _id + AposRelationship: + description: | + The stored value of a relationship field. For multi-select joins,this is an array of entries. + For `max: 1`, treat it as either a single entry or null. + An entry always contains at least the related `_id`; additional keys may appear if `fields` were defined. + oneOf: + - $ref: '#/components/schemas/RelationshipEntry' + - type: 'null' + - type: array + items: + $ref: '#/components/schemas/RelationshipEntry' + AposRelationshipReverse: + type: array + items: + $ref: '#/components/schemas/RelationshipEntry' + description: Populated reverse relationships at read time. Not persistedon this document; useful in responses. + AposObjectId: + type: string + pattern: ^[a-fA-F0-9]{24}$ + description: MongoDB ObjectId (24 hex chars) + AposObjectIdArray: + type: array + items: + $ref: '#/components/schemas/AposPrimitives/$defs/AposObjectId' + AposJSON: + type: object + additionalProperties: true + AposJSONArray: + type: array + items: + $ref: '#/components/schemas/AposPrimitives/$defs/AposJSON' + NullableString: + type: + - string + - 'null' + NullableInteger: + type: + - integer + - 'null' + NullableNumber: + type: + - number + - 'null' + NullableBoolean: + type: + - boolean + - 'null' + NullableObjectId: + type: + - string + - 'null' + pattern: ^[a-fA-F0-9]{24}$ + title: AposPrimitives + + responses: + BadRequest: + description: Bad request - invalid input parameters + content: + application/json: + schema: + type: object + properties: + error: + type: string + example: "Invalid request parameters" + message: + type: string + example: "The request could not be processed due to invalid input" + + Unauthorized: + description: Authentication required + content: + application/json: + schema: + type: object + properties: + error: + type: string + example: "Unauthorized" + message: + type: string + example: "Authentication is required to access this resource" + + Forbidden: + description: Access forbidden - insufficient permissions + content: + application/json: + schema: + type: object + properties: + error: + type: string + example: "Forbidden" + message: + type: string + example: "You do not have permission to perform this action" + + NotFound: + description: Resource not found + content: + application/json: + schema: + type: object + properties: + error: + type: string + example: "Not Found" + message: + type: string + example: "The requested resource could not be found" + + InternalServerError: + description: Internal server error + content: + application/json: + schema: + type: object + properties: + error: + type: string + example: "Internal Server Error" + message: + type: string + example: "An unexpected error occurred while processing the request" + + PieceOperationSuccess: + description: Operation completed successfully + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + example: true + message: + type: string + example: "Operation completed successfully" + +paths: + # Authentication endpoints + /@apostrophecms/login/login: + post: + tags: + - Authentication + summary: "Login to get authentication token" + description: | + 🚀 **Start here!** Authenticate and receive either a bearer token or session cookie for subsequent API requests. + + **Perfect for:** + - Getting started with the API + - Setting up authentication for your app + - Testing API access + + **Choose your authentication method:** + - **Bearer Token** (recommended): omit `session` field or set to `false` + - **Session Cookie**: set `session` to `true` and include `credentials: 'include'` in fetch + operationId: AuthLogin + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - username + - password + properties: + username: + type: string + description: User's login username + example: "admin" + password: + type: string + format: password + description: User's password + session: + type: boolean + description: Set to true to receive session cookie instead of bearer token + default: false + example: false + examples: + bearer_token: + summary: "Request bearer token (recommended)" + value: + username: "admin" + password: "your-password" + session_cookie: + summary: "Request session cookie" + value: + username: "admin" + password: "your-password" + session: true + responses: + '200': + description: Login successful + content: + application/json: + schema: + type: object + properties: + token: + type: string + description: Bearer token (only present when session is false/omitted) + example: "random123Token456xyz" + examples: + bearer_response: + summary: "Bearer token response" + value: + token: "random123Token456xyz" + session_response: + summary: "Session cookie response (token field not present)" + value: {} + headers: + Set-Cookie: + description: Session cookie (only when session=true) + schema: + type: string + example: "apostrophe.sid=s%3A...; Path=/; HttpOnly" + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '500': + $ref: '#/components/responses/InternalServerError' + security: [] + + /@apostrophecms/login/logout: + post: + tags: + - Authentication + summary: "Logout and invalidate session" + description: | + End the current session or invalidate the bearer token. + + **For bearer token**: include Authorization header + **For session cookie**: include credentials in request + operationId: AuthLogout + responses: + '200': + description: Logout successful + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + example: true + '401': + $ref: '#/components/responses/Unauthorized' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/login/reset-request: + post: + tags: + - Authentication + summary: "Request password reset" + description: | + Initiates a password reset process by sending a reset link to the user's email address. + + **⚠️ Note:** This endpoint is only available when `passwordReset` is enabled in the login module configuration. + + **Security feature:** The user will not be notified if the email check fails or if the email fails to send. + However, debug information will be output in the server terminal. + operationId: AuthResetRequest + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - email + properties: + email: + type: string + format: email + description: Email address of the user requesting password reset + example: "user@example.com" + responses: + '200': + description: Password reset request processed (always returns success for security) + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + example: true + message: + type: string + example: "If an account with that email exists, a password reset link has been sent." + '400': + $ref: '#/components/responses/BadRequest' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: [] + + /@apostrophecms/login/reset: + post: + tags: + - Authentication + summary: "Complete password reset" + description: | + Completes a password reset using the token provided in the reset email. + + **⚠️ Note:** This endpoint is only available when `passwordReset` is enabled in the login module configuration. + + Reset tokens are valid for the number of hours specified in `passwordResetHours` (default: 48 hours). + operationId: AuthReset + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - token + - password + properties: + token: + type: string + description: Reset token from the password reset email + example: "reset-token-from-email" + password: + type: string + format: password + description: New password for the user account + example: "new-secure-password" + responses: + '200': + description: Password reset completed successfully + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + example: true + message: + type: string + example: "Password has been reset successfully" + '400': + $ref: '#/components/responses/BadRequest' + '404': + $ref: '#/components/responses/NotFound' + '410': + description: Reset token expired + content: + application/json: + schema: + type: object + properties: + error: + type: string + example: "Reset token has expired" + '500': + $ref: '#/components/responses/InternalServerError' + security: [] + + /@apostrophecms/login/whoami: + get: + tags: + - Authentication + summary: "Get current user information" + deprecated: true + description: | + **⚠️ DEPRECATED:** This GET endpoint is deprecated due to caching issues. + Use the POST method instead. + + Returns information about the currently authenticated user. + + **Security note:** Only explicitly configured fields are returned, + never the complete user object. This prevents accidental exposure + of sensitive user data. + operationId: AuthWhoAmI + responses: + '200': + description: Current user information retrieved successfully + content: + application/json: + schema: + type: object + properties: + _id: + type: string + description: User's unique identifier + example: "user123" + username: + type: string + description: User's login username + example: "john-doe" + title: + type: string + description: User's display name + example: "John Doe" + email: + type: string + format: email + description: User's email address (if configured in whoamiFields) + example: "john@example.com" + additionalProperties: true + description: Additional fields based on whoamiFields configuration + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + post: + tags: + - Authentication + summary: "Get current user information" + description: | + Returns information about the currently authenticated user. + + **Note:** POST method is recommended for this endpoint to avoid caching issues. + + **Perfect for:** + - Checking if authentication is working + - Getting user details for your app + - Validating permissions + + **Security note:** Only explicitly configured fields are returned, + never the complete user object. This prevents accidental exposure + of sensitive user data. + operationId: AuthWhoAmIPost + responses: + '200': + description: Current user information retrieved successfully + content: + application/json: + schema: + type: object + properties: + _id: + type: string + description: User's unique identifier + example: "user123" + username: + type: string + description: User's login username + example: "john-doe" + title: + type: string + description: User's display name + example: "John Doe" + email: + type: string + format: email + description: User's email address (if configured in whoamiFields) + example: "john@example.com" + additionalProperties: true + description: Additional fields based on whoamiFields configuration + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/login/context: + get: + tags: + - Authentication + summary: "Get login context information" + deprecated: true + description: | + **⚠️ DEPRECATED:** This GET endpoint is deprecated due to caching issues. + Use the POST method instead. + + Returns login context information including environment and requirements. + This endpoint provides information about the login system configuration. + + **Useful for:** + - Understanding available login methods + - Checking if password reset is enabled + - Getting login system configuration + operationId: AuthContext + responses: + '200': + description: Login context retrieved successfully + content: + application/json: + schema: + type: object + properties: + localLogin: + type: boolean + description: Whether local login is enabled + example: true + passwordReset: + type: boolean + description: Whether password reset is enabled + example: false + loginUrl: + type: string + description: The configured login URL + example: "/login" + additionalProperties: true + description: Additional context based on configuration + '400': + $ref: '#/components/responses/BadRequest' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + post: + tags: + - Authentication + summary: "Get login context information" + description: | + Returns login context information including environment and requirements. + This endpoint provides information about the login system configuration. + + **Note:** POST method is recommended for this endpoint to avoid caching issues. + + **Useful for:** + - Understanding available login methods + - Checking if password reset is enabled + - Getting login system configuration + operationId: AuthContextPost + responses: + '200': + description: Login context retrieved successfully + content: + application/json: + schema: + type: object + properties: + localLogin: + type: boolean + description: Whether local login is enabled + example: true + passwordReset: + type: boolean + description: Whether password reset is enabled + example: false + loginUrl: + type: string + description: The configured login URL + example: "/login" + additionalProperties: true + description: Additional context based on configuration" + '400': + $ref: '#/components/responses/BadRequest' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + # Page endpoints + /@apostrophecms/page: + get: + tags: + - Pages + summary: Get page tree + description: | + 🚀 **Essential for headless sites!** Fetch your site's complete page structure and content. + + **Perfect for:** + - Building navigation menus + - Getting all pages for static site generation + - Fetching content for SPA routing + - Understanding your site structure + + Returns the complete page hierarchy starting from the home page. Use `flat=1` to get pages in a flat array instead of nested structure. + operationId: PageGet + parameters: + - $ref: '#/components/parameters/AllPages' + - $ref: '#/components/parameters/FlatResponse' + - $ref: '#/components/parameters/ChildrenParam' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + responses: + '200': + description: Page tree retrieved successfully + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PageTreeResponse' + - $ref: '#/components/schemas/FlatPageResponse' + examples: + tree_response: + summary: Nested page tree (default) + value: + _id: "ckhdscx5900054z9k88uqs16w" + title: "Home Page" + slug: "/" + type: "@apostrophecms/home-page" + _children: [] + flat_response: + summary: Flat array response (with flat=1) + value: + results: [] + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + - {} + + post: + tags: + - Pages + summary: Create new page + description: | + Insert a new page at the specified position in the page tree. + + **Perfect for:** + - Programmatically creating pages + - Building page management interfaces + - Migrating content from other systems + + Requires `_targetId` and `_position` to determine placement in the page tree. + operationId: PagePost + parameters: + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PageCreateRequest' + examples: + new_page: + summary: Create new page as first child + value: + title: "New Page" + _targetId: "ckhdscx5900054z9k88uqs16w" + _position: "firstChild" + copy_page: + summary: Create page by copying existing one + value: + title: "Copied Page" + _targetId: "_home" + _position: "lastChild" + _copyingId: "existing-page-id" + responses: + '200': + description: Page created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Page' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/page/archive: + post: + tags: + - Pages + summary: Archive pages + description: Archive pages in bulk, making them inactive while preserving their data in the page tree + operationId: PageArchive + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + _ids: + type: array + items: + type: string + description: Array of page IDs to archive + example: ["page1-id", "page2-id"] + responses: + '200': + description: Archive job started successfully + content: + application/json: + schema: + type: object + properties: + jobId: + type: string + description: ID of the background job processing the archive operation + example: "b4kef9mgstbi5trzsw5dyfqm" + required: + - jobId + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/page/localize: + post: + tags: + - Pages + summary: Localize pages + description: Create or update localized versions of pages in bulk for different languages/regions + operationId: PageLocalize + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + _ids: + type: array + items: + type: string + description: Array of page IDs to localize + example: ["page1-id", "page2-id"] + toLocale: + type: string + description: Target locale for localization + example: "es" + responses: + '200': + description: Pages localized successfully + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Page' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/page/publish: + post: + tags: + - Pages + summary: Publish pages + description: Publish pages in bulk, making them live and visible to end users in the page tree + operationId: PagePublish + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + _ids: + type: array + items: + type: string + description: Array of page IDs to publish + example: ["page1-id", "page2-id"] + responses: + '200': + description: Pages published successfully + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Page' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/page/restore: + post: + tags: + - Pages + summary: Restore pages + description: Restore previously archived pages in bulk, making them active again in the page tree + operationId: PageRestore + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BulkOperationRequest' + responses: + '200': + description: Pages restored successfully + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Page' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/page/{_id}: + delete: + tags: + - Pages + summary: Delete page + description: | + ⚠️ **Permanently delete a page document.** This cannot be undone. + + **Important**: This endpoint should be used to delete the draft version of a page. If the page has been published, you should unpublish it first using the unpublish endpoint + to ensure complete removal. + + **Recommended deletion workflow**: + 1. Unpublish the page (removes published version) + 2. Delete the page (removes draft version) + + **Restrictions:** + - Cannot delete home page + - Cannot delete pages with children (delete children first) + - Cannot delete draft if published version exists + ⚠️ **Permanently delete a page document.** This cannot be undone. + + **Use with caution!** + operationId: PageDeleteById + parameters: + - $ref: '#/components/parameters/DocumentId' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + responses: + '200': + description: Page deleted successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Page' + '400': + description: Deletion not allowed + content: + application/json: + schema: + type: object + properties: + name: + type: string + example: "invalid" + data: + type: object + message: + type: string + example: "You must delete the children of this page first." + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + get: + tags: + - Pages + summary: Get page by ID + description: | + Fetch a single page document by ID for detailed content access. + + **Perfect for:** + - Getting page content for rendering + - Fetching specific page data + - Building page detail views + + The ID can include mode and locale (e.g., `id:en:published`) or use query parameters to specify them. + operationId: PageGetById + parameters: + - $ref: '#/components/parameters/DocumentId' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/RenderAreas' + responses: + '200': + description: Page retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Page' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + - {} + + patch: + tags: + - Pages + summary: Update page + description: | + Partially update a page document. + + **Perfect for:** + - Updating page titles or content + - Moving pages within the tree + - Making incremental changes + + Can use MongoDB-style operators and dot notation for nested properties. Include `_targetId` and `_position` to move the page within the tree. + operationId: PagePatchById + parameters: + - $ref: '#/components/parameters/DocumentId' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + anyOf: + - $ref: '#/components/schemas/PageUpdateRequest' + - $ref: '#/components/schemas/PageDotNotationUpdate' + examples: + update_title: + summary: Update page title only + value: + title: "Updated Page Title" + move_page: + summary: Move page to new position + value: + _targetId: "target-page-id" + _position: "after" + archive_page: + summary: Move page to archive + value: + _targetId: "_archive" + _position: "lastChild" + dot_notation: + summary: Update nested content with dot notation + value: + "description.items.0.content": "

Updated content

" + responses: + '200': + description: Page updated successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Page' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + put: + tags: + - Pages + summary: Replace page + description: | + Completely replace a page document. + + **Use cases:** + - Complete page updates + - Moving pages in the tree structure + - Replacing page content entirely + + Requires `_targetId` and `_position` for page tree positioning. + operationId: PagePutById + parameters: + - $ref: '#/components/parameters/DocumentId' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/RenderAreas' + requestBody: + required: true + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/PageCreateRequest' + - type: object + required: + - _targetId + - _position + responses: + '200': + description: Page replaced successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Page' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/page/{_id}/dismiss-submission: + post: + tags: + - Pages + summary: Dismiss page submission + description: Dismiss a pending submission for the specified page, removing it from the review queue + operationId: PageDismissSubmissionById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Page submission dismissed successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Page' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/page/{_id}/locale/{toLocale}: + get: + tags: + - Pages + summary: Get page in specific locale + description: Retrieve the specified page in a specific locale + operationId: PageGetLocaleById + parameters: + - $ref: '#/components/parameters/DocumentId' + - $ref: '#/components/parameters/ToLocale' + responses: + '200': + description: Page locale retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Page' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/page/{_id}/locales: + get: + tags: + - Pages + summary: Get page locales + description: Retrieve all available locales for the specified page + operationId: PageGetLocalesById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Page locales retrieved successfully + content: + application/json: + schema: + type: object + properties: + results: + type: array + items: + type: object + properties: + _id: + type: string + description: Document ID with locale and mode + example: "s9gjqtw1ok7wxvewdu78xnes:en:published" + aposLocale: + type: string + description: Locale identifier with mode + example: "en:published" + required: + - _id + - aposLocale + required: + - results + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/page/{_id}/localize: + post: + tags: + - Pages + summary: Localize page + description: Create a localized version of the specified page for a specific language/region + operationId: PageLocalizeById + parameters: + - $ref: '#/components/parameters/DocumentId' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + toLocale: + type: string + description: Target locale for localization + example: "es" + responses: + '200': + description: Page localized successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Page' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/page/{_id}/publish: + post: + tags: + - Pages + summary: Publish page + description: | + **Advanced Feature**: Publish a draft page to make it live. + + Moves a page from draft mode to published mode, making it visible + to public users. Essential for content workflows where editors + create drafts before publishing. + + **Use cases:** + - Content approval workflows + - Scheduled publishing systems + - Editorial review processes + + The `_id` can be from either the draft or published version, + or you can use the `aposDocId` to reference the document. + operationId: PagePublishById + parameters: + - $ref: '#/components/parameters/DocumentId' + - $ref: '#/components/parameters/AposLocale' + responses: + '200': + description: Page published successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Page' + examples: + published_page: + summary: Successfully published page + value: + _id: "ckhdscx5900054z9k88uqs16w:en:published" + title: "My Published Page" + slug: "/my-published-page" + type: "default-page" + _url: "https://example.com/my-published-page" + updatedAt: "2024-12-18T10:30:00.000Z" + '400': + description: Bad request - cannot publish (e.g., validation errors) + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + examples: + validation_error: + summary: Page validation failed + value: + error: "Validation failed" + message: "Page title is required before publishing" + '401': + $ref: '#/components/responses/Unauthorized' + '403': + description: Forbidden - insufficient permissions to publish pages + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + '404': + description: Page not found or no draft version exists + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + examples: + no_draft: + summary: No draft version to publish + value: + error: "Not Found" + message: "No draft version of this page exists" + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/page/{_id}/revert-draft-to-published: + post: + tags: + - Pages + summary: Revert draft to published + description: Revert the draft version of the specified page back to its published state + operationId: PageRevertDraftToPublishedById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Page draft reverted to published successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Page' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/page/{_id}/revert-published-to-previous: + post: + tags: + - Pages + summary: Revert published to previous + description: Revert the published version of the specified page to its previous published state + operationId: PageRevertPublishedToPreviousById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Page published version reverted to previous successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Page' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/page/{_id}/share: + post: + tags: + - Pages + summary: Share page + description: Generate a sharing link or configure sharing permissions for the specified page + operationId: PageShareById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Page shared successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Page' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/page/{_id}/submit: + post: + tags: + - Pages + summary: Submit page + description: Submit the specified page for review and approval workflow + operationId: PageSubmitById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Page submitted successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Page' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/page/{_id}/unpublish: + post: + tags: + - Pages + summary: Unpublish page + description: Unpublish the specified page, removing it from public visibility while preserving the content + operationId: PageUnpublishById + parameters: + - $ref: '#/components/parameters/DocumentId' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + responses: + '200': + description: Page unpublished successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Page' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + # Built-in piece types + # User + /@apostrophecms/user: + get: + tags: + - Users + summary: List users + description: Retrieve a list of users with optional filtering, sorting, and pagination + operationId: UserList + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + results: + type: array + items: + $ref: '#/components/schemas/User' + pages: + type: integer + description: Total number of pages + currentPage: + type: integer + description: Current page number + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + post: + tags: + - Users + summary: Create user + description: Create a new user account with the specified properties + operationId: UserCreate + parameters: + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - title + - username + - email + properties: + title: + type: string + description: Display name for the user + example: "John Doe" + username: + type: string + description: Unique username for login + example: "johndoe" + email: + type: string + format: email + description: User's email address + example: "john.doe@example.com" + password: + type: string + format: password + description: User's password + example: "securePassword123" + firstName: + type: string + description: User's first name + example: "John" + lastName: + type: string + description: User's last name + example: "Doe" + role: + type: string + description: User's role/permission level + example: "editor" + disabled: + type: boolean + description: Whether the user account is disabled + default: false + responses: + '200': + description: User created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '409': + description: Conflict - username or email already exists + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/user/archive: + post: + tags: + - Users + summary: Archive users + description: Archive multiple users, making them inactive while preserving their data + operationId: UserArchive + responses: + '200': + description: Archive job started successfully + content: + application/json: + schema: + type: object + properties: + jobId: + type: string + description: ID of the background job processing the archive operation + example: "b4kef9mgstbi5trzsw5dyfqm" + required: + - jobId + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/user/localize: + post: + tags: + - Users + summary: Localize users + description: Create or update localized versions of users for different languages/regions + operationId: UserLocalize + responses: + '200': + description: Users localized successfully + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/User' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/user/publish: + post: + tags: + - Users + summary: Publish users + description: Publish multiple users, making them live and visible + operationId: UserPublish + responses: + '200': + description: Users published successfully + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/User' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/user/restore: + post: + tags: + - Users + summary: Restore users + description: Restore previously archived users, making them active again + operationId: UserRestore + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BulkOperationRequest' + responses: + '200': + description: Users restored successfully + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/User' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/user/{_id}: + delete: + tags: + - Users + summary: Delete user + description: Permanently delete a specific user by ID (requires appropriate permissions) + operationId: UserDeleteById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: User deleted successfully + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + get: + tags: + - Users + summary: Get user + description: Retrieve a specific user by ID + operationId: UserGetById + parameters: + - $ref: '#/components/parameters/DocumentId' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/RenderAreas' + responses: + '200': + description: User retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + patch: + tags: + - Users + summary: Update user + description: Partially update a specific user by ID using PATCH semantics + operationId: UserPatchById + parameters: + - $ref: '#/components/parameters/DocumentId' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + title: + type: string + description: Display name for the user + example: "John Doe" + email: + type: string + format: email + description: User's email address + example: "john.doe@example.com" + firstName: + type: string + description: User's first name + example: "John" + lastName: + type: string + description: User's last name + example: "Doe" + role: + type: string + description: User's role/permission level + example: "editor" + disabled: + type: boolean + description: Whether the user account is disabled + responses: + '200': + description: User updated successfully + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + put: + tags: + - Users + summary: Replace user + description: Completely replace a specific user by ID using PUT semantics + operationId: UserPutById + parameters: + - $ref: '#/components/parameters/DocumentId' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - title + - username + - email + properties: + title: + type: string + description: Display name for the user + example: "John Doe" + username: + type: string + description: Unique username for login + example: "johndoe" + email: + type: string + format: email + description: User's email address + example: "john.doe@example.com" + firstName: + type: string + description: User's first name + example: "John" + lastName: + type: string + description: User's last name + example: "Doe" + role: + type: string + description: User's role/permission level + example: "editor" + disabled: + type: boolean + description: Whether the user account is disabled + default: false + responses: + '200': + description: User replaced successfully + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/user/{_id}/dismiss-submission: + post: + tags: + - Users + summary: Dismiss user submission + description: Dismiss a pending submission for the specified user, removing it from the review queue + operationId: UserDismissSubmissionById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: User submission dismissed successfully + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/user/{_id}/locale/{toLocale}: + get: + tags: + - Users + summary: Get user locale + description: Retrieve the specified user in a specific locale + operationId: UserGetLocaleById + parameters: + - $ref: '#/components/parameters/DocumentId' + - $ref: '#/components/parameters/ToLocale' + responses: + '200': + description: User locale retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/user/{_id}/locales: + get: + tags: + - Users + summary: Get user locales + description: Retrieve all available locales for the specified user + operationId: UserGetLocalesById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: User locales retrieved successfully + content: + application/json: + schema: + type: array + items: + type: string + example: ["en", "es", "fr", "de"] + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/user/{_id}/localize: + post: + tags: + - Users + summary: Localize user + description: Create a localized version of the specified user for a specific language/region + operationId: UserLocalizeById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: User localized successfully + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/user/{_id}/publish: + post: + tags: + - Users + summary: Publish user + description: Publish the specified user, making them live and visible + operationId: UserPublishById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: User published successfully + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/user/{_id}/revert-draft-to-published: + post: + tags: + - Users + summary: Revert draft to published + description: Revert the draft version of the specified user back to its published state + operationId: UserRevertDraftToPublishedById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: User draft reverted to published successfully + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/user/{_id}/revert-published-to-previous: + post: + tags: + - Users + summary: Revert published to previous + description: Revert the published version of the specified user to its previous published state + operationId: UserRevertPublishedToPreviousById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: User published version reverted to previous successfully + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/user/{_id}/share: + post: + tags: + - Users + summary: Share user + description: Generate a sharing link or configure sharing permissions for the specified user + operationId: UserShareById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: User shared successfully + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/user/{_id}/submit: + post: + tags: + - Users + summary: Submit user + description: Submit the specified user for review and approval workflow + operationId: UserSubmitById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: User submitted successfully + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/user/{_id}/unpublish: + post: + tags: + - Users + summary: Unpublish user + description: Unpublish the specified user, removing them from public visibility while preserving the content + operationId: UserUnpublishById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: User unpublished successfully + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + # Global + /@apostrophecms/global: + get: + tags: + - Global Content + summary: Get global content + description: Retrieve global site configuration and content that appears across all pages + operationId: GlobalGet + parameters: + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + responses: + '200': + description: Successful response + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/PaginatedResponse' + - type: object + properties: + results: + type: array + items: + $ref: '#/components/schemas/Global' + + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + post: + tags: + - Global Content + summary: Update global content + description: Update global site configuration and content (requires editor permissions or higher) + operationId: GlobalPost + parameters: + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + title: + type: string + description: Global content title + example: "Site Global Settings" + footerContent: + type: string + description: Footer content that appears on all pages + example: "© 2024 My Website. All rights reserved." + contactInfo: + type: object + description: Site-wide contact information + properties: + email: + type: string + format: email + example: "contact@example.com" + phone: + type: string + example: "+1 (555) 123-4567" + address: + type: string + example: "123 Main St, City, State 12345" + socialMedia: + type: object + description: Social media links + properties: + facebook: + type: string + format: uri + example: "https://facebook.com/mysite" + twitter: + type: string + format: uri + example: "https://twitter.com/mysite" + linkedin: + type: string + format: uri + example: "https://linkedin.com/company/mysite" + siteSettings: + type: object + description: Global site configuration + properties: + siteName: + type: string + example: "My Website" + tagline: + type: string + example: "Welcome to our amazing site" + maintenanceMode: + type: boolean + default: false + responses: + '200': + description: Global content updated successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Global' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/global/archive: + post: + tags: + - Global Content + summary: Archive global document + description: Archive the global document, making it inactive while preserving its data + operationId: GlobalArchive + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BulkOperationRequest' + responses: + '200': + description: Archive job started successfully + content: + application/json: + schema: + type: object + properties: + jobId: + type: string + description: ID of the background job processing the archive operation + example: "b4kef9mgstbi5trzsw5dyfqm" + required: + - jobId + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/global/localize: + post: + tags: + - Global Content + summary: Localize global document + description: Create or update localized versions of the global document for different languages/regions + operationId: GlobalLocalize + responses: + '200': + description: Global localized successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Global' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/global/publish: + post: + tags: + - Global Content + summary: Publish global document + description: Publish the global document, making it live and visible to end users + operationId: GlobalPublish + responses: + '200': + description: Global published successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Global' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/global/restore: + post: + tags: + - Global Content + summary: Restore global document + description: Restore a previously archived global document, making it active again + operationId: GlobalRestore + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BulkOperationRequest' + responses: + '200': + description: Global restored successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Global' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/global/{_id}: + delete: + tags: + - Global Content + summary: Delete global document + description: Permanently delete a specific global document by ID (requires appropriate permissions) + operationId: GlobalDeleteById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Global deleted successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Global' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + get: + tags: + - Global Content + summary: Get global document + description: Retrieve a specific global document by ID (requires appropriate permissions) + operationId: GlobalGetById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Global retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Global' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + patch: + tags: + - Global Content + summary: Update global document + description: | + Partially update a specific global document by ID using PATCH semantics. + Writes must target the draft mode. + operationId: GlobalPatchById + parameters: + - $ref: '#/components/parameters/DocumentId' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/GlobalPatch' + responses: + '200': + description: Global updated successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Global' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + put: + tags: + - Global Content + summary: Replace global document + description: Completely replace a specific global document by ID using PUT semantics + operationId: GlobalPutById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Global replaced successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Global' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/global/{_id}/dismiss-submission: + post: + tags: + - Global Content + summary: Dismiss global submission + description: Dismiss a pending submission for the specified global document, removing it from the review queue + operationId: GlobalDismissSubmissionById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Global submission dismissed successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Global' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/global/{_id}/locale/{toLocale}: + get: + tags: + - Global Content + summary: Get global document locale + description: Retrieve the specified global document in a specific locale + operationId: GlobalGetLocaleById + parameters: + - $ref: '#/components/parameters/DocumentId' + - $ref: '#/components/parameters/ToLocale' + responses: + '200': + description: Global locale retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Global' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/global/{_id}/locales: + get: + tags: + - Global Content + summary: Get global document locales + description: Retrieve all available locales for the specified global document + operationId: GlobalGetLocalesById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Global locales retrieved successfully + content: + application/json: + schema: + type: array + items: + type: string + example: ["en", "es", "fr", "de"] + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/global/{_id}/localize: + post: + tags: + - Global Content + summary: Localize global document + description: Create a localized version of the specified global document for a specific language/region + operationId: GlobalLocalizeById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Global localized successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Global' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/global/{_id}/publish: + post: + tags: + - Global Content + summary: Publish global document + description: Publish the specified global document, making it live and visible to end users + operationId: GlobalPublishById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Global published successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Global' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/global/{_id}/revert-draft-to-published: + post: + tags: + - Global Content + summary: Revert draft to published + description: Revert the draft version of the specified global document back to its published state + operationId: GlobalRevertDraftToPublishedById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Global draft reverted to published successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Global' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/global/{_id}/revert-published-to-previous: + post: + tags: + - Global Content + summary: Revert published to previous + description: Revert the published version of the specified global document to its previous published state + operationId: GlobalRevertPublishedToPreviousById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Global published version reverted to previous successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Global' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/global/{_id}/share: + post: + tags: + - Global Content + summary: Share global document + description: Generate a sharing link or configure sharing permissions for the specified global document + operationId: GlobalShareById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Global shared successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Global' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/global/{_id}/submit: + post: + tags: + - Global Content + summary: Submit global document + description: Submit the specified global document for review and approval workflow + operationId: GlobalSubmitById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Global submitted successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Global' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/global/{_id}/unpublish: + post: + tags: + - Global Content + summary: Unpublish global document + description: Unpublish the specified global document, removing it from public visibility while preserving the content + operationId: GlobalUnpublishById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Global unpublished successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Global' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + # Image + /@apostrophecms/image: + get: + tags: + - Media + summary: Get images + description: | + Retrieve images from the media library. + Authentication is required for all requests other than GET requests + for images with defined publicApiProjection. + operationId: ImageGet + parameters: + - $ref: '#/components/parameters/Page' + - $ref: '#/components/parameters/PerPage' + - $ref: '#/components/parameters/Search' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/RenderAreas' + responses: + '200': + description: Images retrieved successfully + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/PaginatedResponse' + - type: object + properties: + results: + type: array + items: + $ref: '#/components/schemas/Image' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + - {} # Allows unauthenticated access if publicApiProjection is defined + + post: + tags: + - Media + summary: Create image + description: Create a new image document (requires prior attachment upload) + operationId: ImagePost + parameters: + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - title + - attachment + properties: + title: + type: string + example: "Beautiful Landscape" + attachment: + $ref: '#/components/schemas/Attachment' + description: Attachment object from upload endpoint + alt: + type: string + description: Alt text for accessibility + example: "A beautiful mountain landscape at sunset" + credit: + type: string + description: Photo credit + example: "Photo by John Doe" + responses: + '200': + description: Image created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Image' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/image/archive: + post: + tags: + - Media + summary: Archive images + description: Archive multiple images, making them inactive while preserving their data + operationId: ImageArchive + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BulkOperationRequest' + responses: + '200': + description: Archive job started successfully + content: + application/json: + schema: + type: object + properties: + jobId: + type: string + description: ID of the background job processing the archive operation + example: "b4kef9mgstbi5trzsw5dyfqm" + required: + - jobId + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/image/autocrop: + post: + tags: + - Media + summary: Auto-crop images + description: Automatically crop uploaded images using intelligent cropping algorithms + operationId: ImageAutocrop + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + _ids: + type: array + items: + type: string + description: Array of image IDs to auto-crop + cropRatio: + type: string + description: Desired aspect ratio for cropping + example: "16:9" + responses: + '200': + description: Images auto-cropped successfully + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Image' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/image/localize: + post: + tags: + - Media + summary: Localize images + description: Create or update localized versions of images for different languages/regions + operationId: ImageLocalize + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + _ids: + type: array + items: + type: string + description: Array of image IDs to localize + toLocale: + type: string + description: Target locale for localization + example: "es" + responses: + '200': + description: Images localized successfully + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Image' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/image/publish: + post: + tags: + - Media + summary: Publish images + description: Bulk publish multiple images, making them live and visible to end users + operationId: ImagePublish + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + _ids: + type: array + items: + type: string + description: Array of image IDs to publish + responses: + '200': + description: Images published successfully + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Image' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/image/restore: + post: + tags: + - Media + summary: Restore images + description: Restore previously archived images, making them active again + operationId: ImageRestore + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BulkOperationRequest' + responses: + '200': + description: Images restored successfully + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Image' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/image/tag: + post: + tags: + - Media + summary: Tag images + description: Add tags to multiple images for better organization and searchability + operationId: ImageTag + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + _ids: + type: array + items: + type: string + description: Array of image IDs to tag + tags: + type: array + items: + type: string + description: Array of tags to add to the images + example: ["landscape", "nature", "sunset"] + responses: + '200': + description: Images tagged successfully + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Image' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/image/{_id}: + get: + tags: + - Media + summary: Get image document + description: | + Retrieve a specific image by ID from the media library. + Authentication is required for all requests other than GET requests + for images with defined publicApiProjection. + operationId: ImageGetById + parameters: + - $ref: '#/components/parameters/DocumentId' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/RenderAreas' + responses: + '200': + description: Image retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Image' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + - {} # Allows unauthenticated access if publicApiProjection is defined + + put: + tags: + - Media + summary: Replace image document + description: Completely replace an image document by ID using PUT semantics + operationId: ImagePutById + parameters: + - $ref: '#/components/parameters/DocumentId' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - title + - attachment + properties: + title: + type: string + example: "Beautiful Landscape" + attachment: + $ref: '#/components/schemas/Attachment' + description: Attachment object from upload endpoint + alt: + type: string + description: Alt text for accessibility + example: "A beautiful mountain landscape at sunset" + credit: + type: string + description: Photo credit + example: "Photo by John Doe" + responses: + '200': + description: Image replaced successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Image' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + patch: + tags: + - Media + summary: Update image document + description: Partially update a specific image document by ID using PATCH semantics + operationId: ImagePatchById + parameters: + - $ref: '#/components/parameters/DocumentId' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + title: + type: string + example: "Beautiful Landscape" + alt: + type: string + description: Alt text for accessibility + example: "A beautiful mountain landscape at sunset" + credit: + type: string + description: Photo credit + example: "Photo by John Doe" + description: Only include fields to update + responses: + '200': + description: Image updated successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Image' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + delete: + tags: + - Media + summary: Delete image document + description: Permanently delete a specific image document by ID (requires appropriate permissions) + operationId: ImageDeleteById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Image deleted successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Image' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/image/{_id}/dismiss-submission: + post: + tags: + - Media + summary: Dismiss image submission + description: Dismiss a pending submission for the specified image document, removing it from the review queue + operationId: ImageDismissSubmissionById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Image submission dismissed successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Image' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/image/{_id}/locale/{toLocale}: + get: + tags: + - Media + summary: Get image document locale + description: Retrieve the specified image document in a specific locale + operationId: ImageGetLocaleById + parameters: + - $ref: '#/components/parameters/DocumentId' + - $ref: '#/components/parameters/ToLocale' + responses: + '200': + description: Image locale retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Image' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/image/{_id}/locales: + get: + tags: + - Media + summary: Get image document locales + description: Retrieve all available locales for the specified image document + operationId: ImageGetLocalesById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Image locales retrieved successfully + content: + application/json: + schema: + type: array + items: + type: string + example: ["en", "es", "fr", "de"] + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/image/{_id}/localize: + post: + tags: + - Media + summary: Localize image document + description: Create a localized version of the specified image document for a specific language/region + operationId: ImageLocalizeById + parameters: + - $ref: '#/components/parameters/DocumentId' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + toLocale: + type: string + description: Target locale for localization + example: "es" + responses: + '200': + description: Image localized successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Image' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] - Forbidden: - description: Access forbidden - insufficient permissions - content: - application/json: - schema: - type: object - properties: - error: - type: string - example: "Forbidden" - message: - type: string - example: "You do not have permission to perform this action" + /@apostrophecms/image/{_id}/publish: + post: + tags: + - Media + summary: Publish image document + description: Publish the specified image document, making it live and visible to end users + operationId: ImagePublishById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Image published successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Image' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] - NotFound: - description: Resource not found - content: - application/json: + /@apostrophecms/image/{_id}/revert-draft-to-published: + post: + tags: + - Media + summary: Revert image draft to published + description: Revert the draft version of the specified image document back to its published state + operationId: ImageRevertDraftToPublishedById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Image draft reverted to published successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Image' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/image/{_id}/revert-published-to-previous: + post: + tags: + - Media + summary: Revert image published to previous + description: Revert the published version of the specified image document to its previous published state + operationId: ImageRevertPublishedToPreviousById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Image published version reverted to previous successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Image' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/image/{_id}/share: + post: + tags: + - Media + summary: Share image document + description: Generate a sharing link or configure sharing permissions for the specified image document + operationId: ImageShareById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Image shared successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Image' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/image/{imageId}/src: + get: + tags: + - Media + summary: Get image source URL + description: Retrieve the source URL for a specific image, with optional size and format parameters + operationId: ImageGetSrcById + parameters: + - $ref: '#/components/parameters/ImageDocId' + - name: size + in: query + description: Image size variant schema: - type: object - properties: - error: - type: string - example: "Not Found" - message: - type: string - example: "The requested resource could not be found" + type: string + enum: [thumbnail, small, medium, large, original] + default: original + - name: format + in: query + description: Image format + schema: + type: string + enum: [jpg, jpeg, png, webp, avif] + - name: quality + in: query + description: Image quality (1-100) + schema: + type: integer + minimum: 1 + maximum: 100 + default: 80 + responses: + '200': + description: Image source URL retrieved successfully + content: + application/json: + schema: + type: object + properties: + url: + type: string + format: uri + description: Direct URL to the image file + example: "https://example.com/uploads/images/landscape-large.jpg" + width: + type: integer + description: Image width in pixels + example: 1920 + height: + type: integer + description: Image height in pixels + example: 1080 + format: + type: string + description: Image format + example: "jpg" + size: + type: integer + description: File size in bytes + example: 245760 + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + - {} # Allows unauthenticated access for public images + + /@apostrophecms/image/{_id}/submit: + post: + tags: + - Media + summary: Submit image document + description: Submit the specified image document for review and approval workflow + operationId: ImageSubmitById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Image submitted successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Image' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/image/{_id}/unpublish: + post: + tags: + - Media + summary: Unpublish image document + description: Unpublish the specified image document, removing it from public visibility while preserving the content + operationId: ImageUnpublishById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Image unpublished successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Image' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + # Files + /@apostrophecms/file: + get: + tags: + - Media + summary: List files + description: Retrieve a paginated list of files from the media library + operationId: FileGet + parameters: + - $ref: '#/components/parameters/Page' + - $ref: '#/components/parameters/PerPage' + - $ref: '#/components/parameters/Search' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/RenderAreas' + responses: + '200': + description: Files retrieved successfully + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/PaginatedResponse' + - type: object + properties: + results: + type: array + items: + $ref: '#/components/schemas/FileObject' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + - {} # Allows unauthenticated access if publicApiProjection is defined -paths: - # Authentication endpoints - /@apostrophecms/login/login: post: - summary: Login to get bearer token or session cookie - description: | - Authenticate and receive either a bearer token or session cookie for subsequent API requests. - - - For bearer token: omit `session` field or set to `false` - - For session cookie: set `session` to `true` and include `credentials: 'include'` in fetch tags: - - Authentication + - Media + summary: Create file + description: Create a new file document (requires prior attachment upload) + operationId: FilePost + parameters: + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' requestBody: required: true content: @@ -1431,307 +6999,272 @@ paths: schema: type: object required: - - username - - password + - title + - attachment properties: - username: + title: type: string - description: User's login username - example: "admin" - password: + example: "Important Document" + attachment: + $ref: '#/components/schemas/Attachment' + description: Attachment object from upload endpoint + description: type: string - format: password - description: User's password - session: - type: boolean - description: Set to true to receive session cookie instead of bearer token - default: false - example: false - examples: - bearer_token: - summary: Request bearer token - value: - username: "admin" - password: "your-password" - session_cookie: - summary: Request session cookie - value: - username: "admin" - password: "your-password" - session: true + description: File description + example: "Quarterly report PDF" responses: '200': - description: Login successful + description: File created successfully content: application/json: schema: - type: object - properties: - token: - type: string - description: Bearer token (only present when session is false/omitted) - example: "random123Token456xyz" - examples: - bearer_response: - summary: Bearer token response - value: - token: "random123Token456xyz" - session_response: - summary: Session cookie response (token field not present) - value: {} - headers: - Set-Cookie: - description: Session cookie (only when session=true) - schema: - type: string - example: "apostrophe.sid=s%3A...; Path=/; HttpOnly" + $ref: '#/components/schemas/FileObject' + '400': + $ref: '#/components/responses/BadRequest' '401': - description: Invalid credentials + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/file/archive: + post: + tags: + - Media + summary: Archive files + description: Archive multiple files, making them inactive while preserving their data + operationId: FileArchive + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BulkOperationRequest' + responses: + '200': + description: Archive job started successfully content: application/json: schema: type: object properties: - error: + jobId: type: string - example: "Invalid credentials" + description: ID of the background job processing the archive operation + example: "b4kef9mgstbi5trzsw5dyfqm" + required: + - jobId '400': - description: Bad request - missing required fields + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] - /@apostrophecms/login/logout: + /@apostrophecms/file/localize: post: - summary: Logout and invalidate token/session - description: | - End the current session or invalidate the bearer token. - - - For bearer token: include Authorization header - - For session cookie: include credentials in request tags: - - Authentication + - Media + summary: Localize files + description: Create or update localized versions of files for different languages/regions + operationId: FileLocalize responses: '200': - description: Logout successful + description: Files localized successfully content: application/json: schema: - type: object - properties: - success: - type: boolean - example: true + type: array + items: + $ref: '#/components/schemas/FileObject' + '400': + $ref: '#/components/responses/BadRequest' '401': - description: Not authenticated + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' security: + - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - # Page endpoints - /@apostrophecms/page: - get: + /@apostrophecms/file/publish: + post: tags: - - Pages - summary: Get page tree - description: | - Fetch the home page and all other pages structured in the home page's `_children` property. - Returns the complete page hierarchy starting from the home page. - parameters: - - $ref: '#/components/parameters/AllPages' - - $ref: '#/components/parameters/FlatResponse' - - $ref: '#/components/parameters/ChildrenParam' - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' + - Media + summary: Publish files + description: Bulk publish multiple files, making them live and visible to end users + operationId: FilePublish responses: '200': - description: Page tree retrieved successfully + description: Files published successfully content: application/json: schema: - oneOf: - - $ref: '#/components/schemas/PageTreeResponse' - - $ref: '#/components/schemas/FlatPageResponse' - examples: - tree_response: - summary: Tree structure response - value: - _id: "ckhdscx5900054z9k88uqs16w" - title: "Home Page" - slug: "/" - type: "@apostrophecms/home-page" - _children: [] - flat_response: - summary: Flat array response - value: - results: [] + type: array + items: + $ref: '#/components/schemas/FileObject' '400': - description: Bad request - Invalid image ID format - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '404': - description: Page not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' '500': - description: Internal server error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - - {} # Allows unauthenticated access if publicApiProjection is defined + /@apostrophecms/file/restore: post: tags: - - Pages - summary: Create new page - description: | - Insert a new page at the specified position in the page tree. - Requires `_targetId` and `_position` to determine placement. - parameters: - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' + - Media + summary: Restore files + description: Restore previously archived files, making them active again + operationId: FileRestore requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/PageCreateRequest' - examples: - new_page: - summary: Create new page as first child - value: - title: "New Page" - _targetId: "ckhdscx5900054z9k88uqs16w" - _position: "firstChild" - copy_page: - summary: Create page by copying existing one - value: - title: "Copied Page" - _targetId: "_home" - _position: "lastChild" - _copyingId: "existing-page-id" + $ref: '#/components/schemas/BulkOperationRequest' responses: - '201': - description: Page created successfully + '200': + description: Files restored successfully content: application/json: schema: - $ref: '#/components/schemas/PageTreeResponse' + type: array + items: + $ref: '#/components/schemas/FileObject' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - /@apostrophecms/page/{_id}: - get: + /@apostrophecms/file/{_id}: + delete: tags: - - Pages - summary: Get single page - description: | - Fetch a single page document by ID. The ID can include mode and locale - (e.g., `id:en:published`) or use query parameters to specify them. + - Media + summary: Delete file + description: Permanently delete a specific file by ID (requires appropriate permissions) + operationId: FileDeleteById parameters: - - $ref: '#/components/parameters/PageId' + - $ref: '#/components/parameters/DocumentId' - $ref: '#/components/parameters/AposMode' - $ref: '#/components/parameters/AposLocale' - - $ref: '#/components/parameters/RenderAreas' responses: '200': - description: Page retrieved successfully + description: File deleted successfully content: application/json: schema: - $ref: '#/components/schemas/PageTreeResponse' + $ref: '#/components/schemas/FileObject' '400': - description: Bad request - Invalid image ID format - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' '404': - description: Page with that ID doesn't exist - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/NotFound' '500': - description: Internal server error + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + get: + tags: + - Media + summary: Get file by ID + description: Retrieve a specific file by ID from the media library + operationId: FileGetById + parameters: + - $ref: '#/components/parameters/DocumentId' + - $ref: '#/components/parameters/AposMode' + - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/RenderAreas' + responses: + '200': + description: File retrieved successfully content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/schemas/FileObject' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - {} # Allows unauthenticated access if publicApiProjection is defined - put: + patch: tags: - - Pages - summary: Replace page - description: | - Completely replace a page document. Requires `_targetId` and `_position` - for page tree positioning. + - Media + summary: Update file + description: Partially update a specific file by ID using PATCH semantics + operationId: FilePatchById parameters: - - $ref: '#/components/parameters/PageId' + - $ref: '#/components/parameters/DocumentId' - $ref: '#/components/parameters/AposMode' - $ref: '#/components/parameters/AposLocale' - - $ref: '#/components/parameters/RenderAreas' requestBody: required: true content: application/json: schema: - allOf: - - $ref: '#/components/schemas/PageCreateRequest' - - type: object - required: - - _targetId - - _position + type: object + properties: + title: + type: string + description: File title + example: "Important Document" + description: + type: string + description: File description + example: "Quarterly report PDF" + description: Only include fields to update responses: '200': - description: Page replaced successfully + description: File updated successfully content: application/json: schema: - $ref: '#/components/schemas/PageTreeResponse' + $ref: '#/components/schemas/FileObject' '400': $ref: '#/components/responses/BadRequest' '401': @@ -1740,21 +7273,21 @@ paths: $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - patch: + put: tags: - - Pages - summary: Update page - description: | - Partially update a page document. Can use MongoDB-style operators - and dot notation for nested properties. Include `_targetId` and `_position` - to move the page within the tree. + - Media + summary: Replace file + description: Completely replace a specific file by ID using PUT semantics + operationId: FilePutById parameters: - - $ref: '#/components/parameters/PageId' + - $ref: '#/components/parameters/DocumentId' - $ref: '#/components/parameters/AposMode' - $ref: '#/components/parameters/AposLocale' requestBody: @@ -1762,33 +7295,28 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/PageUpdateRequest' - examples: - update_title: - summary: Update page title only - value: - title: "Updated Page Title" - move_page: - summary: Move page to new position - value: - _targetId: "target-page-id" - _position: "after" - archive_page: - summary: Move page to archive - value: - _targetId: "_archive" - _position: "lastChild" - dot_notation: - summary: Update nested content with dot notation - value: - "description.items.0.content": "

Updated content

" + type: object + required: + - title + - attachment + properties: + title: + type: string + example: "Important Document" + attachment: + $ref: '#/components/schemas/Attachment' + description: Attachment object from upload endpoint + description: + type: string + description: File description + example: "Quarterly report PDF" responses: '200': - description: Page updated successfully + description: File replaced successfully content: application/json: schema: - $ref: '#/components/schemas/PageTreeResponse' + $ref: '#/components/schemas/FileObject' '400': $ref: '#/components/responses/BadRequest' '401': @@ -1797,73 +7325,61 @@ paths: $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - delete: + /@apostrophecms/file/{_id}/dismiss-submission: + post: tags: - - Pages - summary: Delete page - description: | - **Permanently delete a page document.** This cannot be undone. - - Restrictions: - - Cannot delete home page - - Cannot delete pages with children (delete children first) - - Cannot delete draft if published version exists + - Media + summary: Dismiss file submission + description: Dismiss a pending submission for the specified file, removing it from the review queue + operationId: FileDismissSubmissionById parameters: - - $ref: '#/components/parameters/PageId' - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/DocumentId' responses: '200': - description: Page deleted successfully - '400': - description: Deletion not allowed + description: File submission dismissed successfully content: application/json: schema: - type: object - properties: - name: - type: string - example: "invalid" - data: - type: object - message: - type: string - example: "You must delete the children of this page first." + $ref: '#/components/schemas/FileObject' + '400': + $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - /@apostrophecms/page/{_id}/publish: - post: + /@apostrophecms/file/{_id}/locale/{toLocale}: + get: tags: - - Pages - summary: Publish page draft - description: | - Publish an existing draft mode document. The `_id` can be from either - the draft or published version, or use the `aposDocId`. + - Media + summary: Get file locale + description: Retrieve the specified file in a specific locale + operationId: FileGetLocaleById parameters: - - $ref: '#/components/parameters/PageId' - - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/DocumentId' + - $ref: '#/components/parameters/ToLocale' responses: '200': - description: Page published successfully + description: File locale retrieved successfully content: application/json: schema: - $ref: '#/components/schemas/PageTreeResponse' + $ref: '#/components/schemas/FileObject' '400': $ref: '#/components/responses/BadRequest' '401': @@ -1872,464 +7388,315 @@ paths: $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - /{_url}: + /@apostrophecms/file/{_id}/locales: get: tags: - - Pages - summary: Get rendered page content - description: | - Get a page's rendered HTML content. With `aposRefresh=1`, returns only - the refreshable content without the full page layout (used by Apostrophe UI). + - Media + summary: Get file locales + description: Retrieve all available locales for the specified file + operationId: FileGetLocalesById parameters: - - name: _url - in: path - required: true - description: Page URL path - schema: - type: string - example: "/about-us" - - name: aposRefresh - in: query - description: Return only refreshable content without full layout - schema: - type: string - enum: ["1"] - example: "1" + - $ref: '#/components/parameters/DocumentId' responses: '200': - description: Page content retrieved successfully + description: File locales retrieved successfully content: - text/html: + application/json: schema: - type: string - description: Rendered HTML content + type: array + items: + type: string + example: ["en", "es", "fr", "de"] + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] - # Built-in piece types - /@apostrophecms/user: - get: - summary: Get users - description: Retrieve users (requires admin permissions) + /@apostrophecms/file/{_id}/localize: + post: tags: - - Users (Built-in) + - Media + summary: Localize file + description: Create a localized version of the specified file for a specific language/region + operationId: FileLocalizeById parameters: - - $ref: '#/components/parameters/Page' - - $ref: '#/components/parameters/PerPage' - - $ref: '#/components/parameters/Search' - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' - - $ref: '#/components/parameters/RenderAreas' + - $ref: '#/components/parameters/DocumentId' responses: '200': - description: Successful response + description: File localized successfully content: application/json: schema: - allOf: - - $ref: '#/components/schemas/PaginatedResponse' - - type: object - properties: - results: - type: array - items: - $ref: '#/components/schemas/User' + $ref: '#/components/schemas/FileObject' + '400': + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - admin required - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - - {} # Allows unauthenticated IF publicApiProjection is defined + /@apostrophecms/file/{_id}/publish: post: - summary: Create user - description: Create a new user account (requires admin permissions) tags: - - Users (Built-in) + - Media + summary: Publish file + description: Publish the specified file, making it live and visible to end users + operationId: FilePublishById parameters: - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' - requestBody: - required: true - content: - application/json: - schema: - type: object - required: - - title - - username - - email - - password - properties: - title: - type: string - example: "Jane Developer" - username: - type: string - example: "janedeveloper" - email: - type: string - format: email - example: "jane@example.com" - password: - type: string - format: password - description: User password - role: - type: string - enum: ["guest", "contributor", "editor", "admin"] - default: "contributor" - disabled: - type: boolean - default: false + - $ref: '#/components/parameters/DocumentId' responses: - '201': - description: User created successfully + '200': + description: File published successfully content: application/json: schema: - $ref: '#/components/schemas/User' + $ref: '#/components/schemas/FileObject' '400': - description: Bad request - validation errors - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - admin required - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - /@apostrophecms/user/{id}: - get: - summary: Get single user - description: Retrieve a specific user by ID (requires appropriate permissions) + /@apostrophecms/file/{_id}/revert-draft-to-published: + post: tags: - - Users (Built-in) + - Media + summary: Revert file draft to published + description: Revert the draft version of the specified file back to its published state + operationId: FileRevertDraftToPublishedById parameters: - - name: id - in: path - required: true - description: User ID - schema: - type: string - example: "clx1234567890abcdef" - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' - - $ref: '#/components/parameters/RenderAreas' + - $ref: '#/components/parameters/DocumentId' responses: '200': - description: User retrieved successfully + description: File draft reverted to published successfully content: application/json: schema: - $ref: '#/components/schemas/User' + $ref: '#/components/schemas/FileObject' '400': - description: Bad request - Invalid user ID format - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - Insufficient permissions to view this user - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' '404': - description: User not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/NotFound' '500': - description: Internal server error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - put: - summary: Replace user - description: Completely replace a user document + /@apostrophecms/file/{_id}/revert-published-to-previous: + post: tags: - - Users (Built-in) + - Media + summary: Revert file published to previous + description: Revert the published version of the specified file to its previous published state + operationId: FileRevertPublishedToPreviousById parameters: - - name: id - in: path - required: true - schema: - type: string - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' - requestBody: - required: true - content: - application/json: - schema: - type: object - required: - - title - - username - - email - properties: - title: - type: string - username: - type: string - email: - type: string - format: email - role: - type: string - enum: ["guest", "contributor", "editor", "admin"] - disabled: - type: boolean + - $ref: '#/components/parameters/DocumentId' responses: '200': - description: User updated + description: File published version reverted to previous successfully content: application/json: schema: - $ref: '#/components/schemas/User' + $ref: '#/components/schemas/FileObject' '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' '404': - description: User not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - patch: - summary: Update user fields - description: Update specific fields of a user + /@apostrophecms/file/{_id}/share: + post: tags: - - Users (Built-in) + - Media + summary: Share file + description: Generate a sharing link or configure sharing permissions for the specified file + operationId: FileShareById parameters: - - name: id - in: path - required: true - schema: - type: string - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - title: - type: string - email: - type: string - format: email - role: - type: string - enum: ["guest", "contributor", "editor", "admin"] - disabled: - type: boolean - description: Only include fields to update + - $ref: '#/components/parameters/DocumentId' responses: '200': - description: User updated + description: File shared successfully content: application/json: schema: - $ref: '#/components/schemas/User' + $ref: '#/components/schemas/FileObject' '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' '404': - description: User not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - delete: - summary: Delete user - description: Permanently delete a user + /@apostrophecms/file/{_id}/submit: + post: tags: - - Users (Built-in) + - Media + summary: Submit file + description: Submit the specified file for review and approval workflow + operationId: FileSubmitById parameters: - - name: id - in: path - required: true - schema: - type: string - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/DocumentId' responses: '200': - description: User deleted - '401': - description: Unauthorized + description: File submitted successfully content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/schemas/FileObject' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' '404': - description: User not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - /@apostrophecms/user/{id}/publish: + /@apostrophecms/file/{_id}/unpublish: post: - summary: Publish user draft - description: Publish the draft version of a user tags: - - Users (Built-in) + - Media + summary: Unpublish file + description: Unpublish the specified file, removing it from public visibility while preserving the content + operationId: FileUnpublishById parameters: - - name: id - in: path - required: true - schema: - type: string - - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/DocumentId' responses: '200': - description: User published + description: File unpublished successfully content: application/json: schema: - $ref: '#/components/schemas/User' + $ref: '#/components/schemas/FileObject' + '400': + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' '404': - description: User not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - /@apostrophecms/global: + # Image-tags + /@apostrophecms/image-tag: get: - summary: Get global content - description: Retrieve site-wide global content and settings tags: - - Global Content (Built-in) + - Media + summary: Get image tags + description: Retrieve image tags for organizing images + operationId: ImageTagGet parameters: + - $ref: '#/components/parameters/Page' + - $ref: '#/components/parameters/PerPage' + - $ref: '#/components/parameters/Search' - $ref: '#/components/parameters/AposMode' - $ref: '#/components/parameters/AposLocale' - $ref: '#/components/parameters/RenderAreas' responses: '200': - description: Global content retrieved + description: Successful response content: application/json: schema: - $ref: '#/components/schemas/Global' + allOf: + - $ref: '#/components/schemas/PaginatedResponse' + - type: object + properties: + results: + type: array + items: + $ref: '#/components/schemas/ImageTag' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - - {} # Allows unauthenticated IF publicApiProjection is defined + - {} # Allows unauthenticated access if publicApiProjection is defined - put: - summary: Update global content - description: Update site-wide global content (requires editor permissions) + post: tags: - - Global Content (Built-in) + - Media + summary: Create image tag + description: Create a new image tag for organizing images + operationId: ImageTagPost parameters: - $ref: '#/components/parameters/AposMode' - $ref: '#/components/parameters/AposLocale' @@ -2339,350 +7706,243 @@ paths: application/json: schema: type: object + required: + - title properties: title: type: string - description: Site title - # Custom fields would be defined in project configuration - description: Fields depend on project configuration + example: "Hero Images" + description: Tag name + slug: + type: string + example: "hero-images" + description: URL-friendly identifier (auto-generated if not provided) responses: '200': - description: Global content updated + description: Image tag created successfully content: application/json: schema: - $ref: '#/components/schemas/Global' + $ref: '#/components/schemas/ImageTag' '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - editor required - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - patch: - summary: Partially update global content - description: Update specific fields in global content without affecting others (requires editor permissions) + /@apostrophecms/image-tag/archive: + post: tags: - - Global Content (Built-in) - parameters: - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' + - Media + summary: Archive image tags + description: Archive multiple image tags, making them inactive while preserving their data + operationId: ImageTagArchive requestBody: required: true content: application/json: schema: - type: object - properties: - title: - type: string - description: Site title - # Custom fields would be defined in project configuration - description: Only include fields you want to update - other fields remain unchanged - additionalProperties: true + $ref: '#/components/schemas/BulkOperationRequest' responses: '200': - description: Global content partially updated + description: Archive job started successfully content: application/json: schema: - $ref: '#/components/schemas/Global' + type: object + properties: + jobId: + type: string + description: ID of the background job processing the archive operation + example: "b4kef9mgstbi5trzsw5dyfqm" + required: + - jobId '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - editor required - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - /@apostrophecms/image: - get: - summary: Get images - description: | - Retrieve images from the media library. - Authentication is required for all requests other than GET requests - for images with defined publicApiProjection. + /@apostrophecms/image-tag/localize: + post: tags: - - Media (Built-in) - parameters: - - $ref: '#/components/parameters/Page' - - $ref: '#/components/parameters/PerPage' - - $ref: '#/components/parameters/Search' - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' - - $ref: '#/components/parameters/RenderAreas' + - Media + summary: Localize image tags + description: Create or update localized versions of image tags for different languages/regions + operationId: ImageTagLocalize responses: '200': - description: Images retrieved successfully + description: Image tags localized successfully content: application/json: schema: - allOf: - - $ref: '#/components/schemas/PaginatedResponse' - - type: object - properties: - results: - type: array - items: - $ref: '#/components/schemas/Image' + type: array + items: + $ref: '#/components/schemas/ImageTag' '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' '500': - description: Internal server error + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/image-tag/publish: + post: + tags: + - Media + summary: Publish image tags + description: Publish multiple image tags, making them live and visible to end users + operationId: ImageTagPublish + responses: + '200': + description: Image tags published successfully content: application/json: schema: - $ref: '#/components/schemas/Error' + type: array + items: + $ref: '#/components/schemas/ImageTag' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - - {} # Allows unauthenticated access if publicApiProjection is defined + /@apostrophecms/image-tag/restore: post: - summary: Create image - description: Create a new image document (requires prior attachment upload) tags: - - Media (Built-in) - parameters: - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' + - Media + summary: Restore image tags + description: Restore previously archived image tags, making them active again + operationId: ImageTagRestore requestBody: - required: true - content: - application/json: - schema: - type: object - required: - - title - - attachment - properties: - title: - type: string - example: "Beautiful Landscape" - attachment: - $ref: '#/components/schemas/Attachment' - description: Attachment object from upload endpoint - alt: - type: string - description: Alt text for accessibility - example: "A beautiful mountain landscape at sunset" - credit: - type: string - description: Photo credit - example: "Photo by John Doe" + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BulkOperationRequest' responses: - '201': - description: Image created successfully + '200': + description: Image tags restored successfully content: application/json: schema: - $ref: '#/components/schemas/Image' + type: array + items: + $ref: '#/components/schemas/ImageTag' '400': - description: Bad request - validation errors - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - /@apostrophecms/image/{id}: - get: - summary: Get single image - description: | - Retrieve a specific image by ID from the media library. - Authentication is required for all requests other than GET requests - for images with defined publicApiProjection. + /@apostrophecms/image-tag/{_id}: + delete: tags: - - Media (Built-in) + - Media + summary: Delete image tag + description: Permanently delete a specific image tag by ID (requires appropriate permissions) + operationId: ImageTagDeleteById parameters: - - name: id - in: path - required: true - description: Image ID - schema: - type: string - example: "clx1234567890abcdef" - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' - - $ref: '#/components/parameters/RenderAreas' + - $ref: '#/components/parameters/DocumentId' responses: '200': - description: Image retrieved successfully + description: Image tag deleted successfully content: application/json: schema: - $ref: '#/components/schemas/Image' + $ref: '#/components/schemas/ImageTag' '400': - description: Bad request - Invalid image ID format - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' '404': - description: Image not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/NotFound' '500': - description: Internal server error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - - {} # Allows unauthenticated access if publicApiProjection is defined - put: - summary: Replace image - description: Completely replace an image document + get: tags: - - Media (Built-in) + - Media + summary: Get image tag + description: Retrieve a specific image tag by ID + operationId: ImageTagGetById parameters: - - name: id - in: path - required: true - schema: - type: string + - $ref: '#/components/parameters/DocumentId' - $ref: '#/components/parameters/AposMode' - $ref: '#/components/parameters/AposLocale' - requestBody: - required: true - content: - application/json: - schema: - type: object - required: - - title - - attachment - properties: - title: - type: string - attachment: - $ref: '#/components/schemas/Attachment' - alt: - type: string - credit: - type: string + - $ref: '#/components/parameters/RenderAreas' responses: '200': - description: Image updated + description: Image tag retrieved successfully content: application/json: schema: - $ref: '#/components/schemas/Image' + $ref: '#/components/schemas/ImageTag' '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' '404': - description: Image not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] + - {} # Allows unauthenticated access if publicApiProjection is defined patch: - summary: Update image fields - description: Update specific fields of an image tags: - - Media (Built-in) + - Media + summary: Update image tag + description: Partially update a specific image tag by ID using PATCH semantics + operationId: ImageTagPatchById parameters: - - name: id - in: path - required: true - schema: - type: string + - $ref: '#/components/parameters/DocumentId' - $ref: '#/components/parameters/AposMode' - $ref: '#/components/parameters/AposLocale' requestBody: @@ -2694,682 +7954,445 @@ paths: properties: title: type: string - alt: - type: string - credit: + example: "Hero Images" + description: Tag name + slug: type: string + example: "hero-images" + description: URL-friendly identifier description: Only include fields to update responses: '200': - description: Image updated + description: Image tag updated successfully content: application/json: schema: - $ref: '#/components/schemas/Image' + $ref: '#/components/schemas/ImageTag' '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' '404': - description: Image not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - delete: - summary: Delete image - description: Permanently delete an image + put: tags: - - Media (Built-in) + - Media + summary: Replace image tag + description: Completely replace a specific image tag by ID using PUT semantics + operationId: ImageTagPutById parameters: - - name: id - in: path - required: true - schema: - type: string + - $ref: '#/components/parameters/DocumentId' - $ref: '#/components/parameters/AposMode' - $ref: '#/components/parameters/AposLocale' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - title + properties: + title: + type: string + example: "Hero Images" + description: Tag name + slug: + type: string + example: "hero-images" + description: URL-friendly identifier (auto-generated if not provided) responses: '200': - description: Image deleted - '401': - description: Unauthorized + description: Image tag replaced successfully content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/schemas/ImageTag' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' '404': - description: Image not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - /@apostrophecms/image/{id}/publish: + /@apostrophecms/image-tag/{_id}/dismiss-submission: post: - summary: Publish image draft - description: Publish the draft version of an image tags: - - Media (Built-in) + - Media + summary: Dismiss image tag submission + description: Dismiss a pending submission for the specified image tag, removing it from the review queue + operationId: ImageTagDismissSubmissionById parameters: - - name: id - in: path - required: true - schema: - type: string - - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/DocumentId' responses: '200': - description: Image published + description: Image tag submission dismissed successfully content: application/json: schema: - $ref: '#/components/schemas/Image' + $ref: '#/components/schemas/ImageTag' + '400': + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' '404': - description: Image not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - /@apostrophecms/file: + /@apostrophecms/image-tag/{_id}/locale/{toLocale}: get: - summary: Get files - description: | - Retrieve files from the media library. - Authentication is required for all requests other than GET requests - for files with defined publicApiProjection. tags: - - Media (Built-in) + - Media + summary: Get image tag locale + description: Retrieve the specified image tag in a specific locale + operationId: ImageTagGetLocaleById parameters: - - $ref: '#/components/parameters/Page' - - $ref: '#/components/parameters/PerPage' - - $ref: '#/components/parameters/Search' - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' - - $ref: '#/components/parameters/RenderAreas' + - $ref: '#/components/parameters/DocumentId' + - $ref: '#/components/parameters/ToLocale' responses: '200': - description: Files retrieved successfully + description: Image tag locale retrieved successfully content: application/json: schema: - allOf: - - $ref: '#/components/schemas/PaginatedResponse' - - type: object - properties: - results: - type: array - items: - $ref: '#/components/schemas/File' + $ref: '#/components/schemas/ImageTag' '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' '500': - description: Internal server error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/InternalServerError' security: - - ApiKeyAuth: [] - - BearerAuth: [] - - SessionAuth: [] - - {} # Allows unauthenticated access if publicApiProjection is defined - - post: - summary: Create file - description: Create a new file document (requires prior attachment upload) - tags: - - Media (Built-in) - parameters: - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' - requestBody: - required: true - content: - application/json: - schema: - type: object - required: - - title - - attachment - properties: - title: - type: string - example: "Important Document" - attachment: - $ref: '#/components/schemas/Attachment' - description: Attachment object from upload endpoint - description: - type: string - description: File description - example: "Quarterly report PDF" + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/image-tag/{_id}/locales: + get: + tags: + - Media + summary: Get image tag locales + description: Retrieve all available locales for the specified image tag + operationId: ImageTagGetLocalesById + parameters: + - $ref: '#/components/parameters/DocumentId' responses: - '201': - description: File created successfully + '200': + description: Image tag locales retrieved successfully content: application/json: schema: - $ref: '#/components/schemas/File' + type: array + items: + type: string + example: ["en", "es", "fr", "de"] '400': - description: Bad request - validation errors - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - /@apostrophecms/file/{id}: - get: - summary: Get single file - description: | - Retrieve a specific file by ID from the media library. - Authentication is required for all requests other than GET requests - for files with defined publicApiProjection. + /@apostrophecms/image-tag/{_id}/localize: + post: tags: - - Media (Built-in) + - Media + summary: Localize image tag + description: Create a localized version of the specified image tag for a specific language/region + operationId: ImageTagLocalizeById parameters: - - name: id - in: path - required: true - description: File ID - schema: - type: string - example: "clx1234567890abcdef" - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' - - $ref: '#/components/parameters/RenderAreas' + - $ref: '#/components/parameters/DocumentId' responses: '200': - description: File retrieved successfully + description: Image tag localized successfully content: application/json: schema: - $ref: '#/components/schemas/File' + $ref: '#/components/schemas/ImageTag' '400': - description: Bad request - Invalid file ID format - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' '404': - description: File not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/NotFound' '500': - description: Internal server error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - - {} # Allows unauthenticated access if publicApiProjection is defined - put: - summary: Replace file - description: Completely replace a file document + /@apostrophecms/image-tag/{_id}/publish: + post: tags: - - Media (Built-in) + - Media + summary: Publish image tag + description: Publish the specified image tag, making it live and visible to end users + operationId: ImageTagPublishById parameters: - - name: id - in: path - required: true - schema: - type: string - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' - requestBody: - required: true - content: - application/json: - schema: - type: object - required: - - title - - attachment - properties: - title: - type: string - attachment: - $ref: '#/components/schemas/Attachment' - description: - type: string + - $ref: '#/components/parameters/DocumentId' responses: '200': - description: File updated + description: Image tag published successfully content: application/json: schema: - $ref: '#/components/schemas/File' + $ref: '#/components/schemas/ImageTag' '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' '404': - description: File not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - patch: - summary: Update file fields - description: Update specific fields of a file + /@apostrophecms/image-tag/{_id}/revert-draft-to-published: + post: tags: - - Media (Built-in) + - Media + summary: Revert draft to published + description: Revert the draft version of the specified image tag back to its published state + operationId: ImageTagRevertDraftToPublishedById parameters: - - name: id - in: path - required: true - schema: - type: string - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - title: - type: string - description: - type: string - description: Only include fields to update + - $ref: '#/components/parameters/DocumentId' responses: '200': - description: File updated + description: Image tag draft reverted to published successfully content: application/json: schema: - $ref: '#/components/schemas/File' + $ref: '#/components/schemas/ImageTag' '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' '404': - description: File not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - delete: - summary: Delete file - description: Permanently delete a file + /@apostrophecms/image-tag/{_id}/revert-published-to-previous: + post: tags: - - Media (Built-in) + - Media + summary: Revert published to previous + description: Revert the published version of the specified image tag to its previous published state + operationId: ImageTagRevertPublishedToPreviousById parameters: - - name: id - in: path - required: true - schema: - type: string - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/DocumentId' responses: '200': - description: File deleted - '401': - description: Unauthorized + description: Image tag published version reverted to previous successfully content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/schemas/ImageTag' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' '404': - description: File not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - /@apostrophecms/file/{id}/publish: + /@apostrophecms/image-tag/{_id}/share: post: - summary: Publish file draft - description: Publish the draft version of a file tags: - - Media (Built-in) + - Media + summary: Share image tag + description: Generate a sharing link or configure sharing permissions for the specified image tag + operationId: ImageTagShareById parameters: - - name: id - in: path - required: true - schema: - type: string - - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/DocumentId' responses: '200': - description: File published + description: Image tag shared successfully content: application/json: schema: - $ref: '#/components/schemas/File' + $ref: '#/components/schemas/ImageTag' + '400': + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' '404': - description: File not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - /@apostrophecms/image-tag: - get: - summary: Get image tags - description: Retrieve image tags for organizing images + /@apostrophecms/image-tag/{_id}/submit: + post: tags: - - Media (Built-in) + - Media + summary: Submit image tag + description: Submit the specified image tag for review and approval workflow + operationId: ImageTagSubmitById parameters: - - $ref: '#/components/parameters/Page' - - $ref: '#/components/parameters/PerPage' - - $ref: '#/components/parameters/Search' - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' - - $ref: '#/components/parameters/RenderAreas' + - $ref: '#/components/parameters/DocumentId' responses: '200': - description: Successful response + description: Image tag submitted successfully content: application/json: schema: - allOf: - - $ref: '#/components/schemas/PaginatedResponse' - - type: object - properties: - results: - type: array - items: - $ref: '#/components/schemas/ImageTag' + $ref: '#/components/schemas/ImageTag' '400': - description: Bad request - Invalid file ID format - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' '404': - description: File not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/NotFound' '500': - description: Internal server error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - - {} # Allows unauthenticated access if publicApiProjection is defined + /@apostrophecms/image-tag/{_id}/unpublish: post: - summary: Create image tag - description: Create a new image tag for organizing images tags: - - Media (Built-in) + - Media + summary: Unpublish image tag + description: Unpublish the specified image tag, removing it from public visibility while preserving the content + operationId: ImageTagUnpublishById parameters: - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' - requestBody: - required: true - content: - application/json: - schema: - type: object - required: - - title - properties: - title: - type: string - example: "Hero Images" - description: Tag name - slug: - type: string - example: "hero-images" - description: URL-friendly identifier (auto-generated if not provided) + - $ref: '#/components/parameters/DocumentId' responses: - '201': - description: Image tag created successfully + '200': + description: Image tag unpublished successfully content: application/json: schema: $ref: '#/components/schemas/ImageTag' '400': - description: Bad request - validation errors - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - /@apostrophecms/image-tag/{id}: + # File-tags + /@apostrophecms/file-tag: get: - summary: Get single image tag - description: Retrieve a specific image tag by ID tags: - - Media (Built-in) + - Media + summary: List file tags + description: Retrieve a list of file tags used for organizing and categorizing uploaded files + operationId: FileTagGet parameters: - - name: id - in: path - required: true - description: Image tag ID - schema: - type: string - example: "clx1234567890abcdef" - $ref: '#/components/parameters/AposMode' - $ref: '#/components/parameters/AposLocale' - $ref: '#/components/parameters/RenderAreas' responses: '200': - description: Image tag found - content: - application/json: - schema: - $ref: '#/components/schemas/ImageTag' - '400': - description: Bad request - Invalid file ID format + description: Successful response content: application/json: schema: - $ref: '#/components/schemas/Error' + type: object + properties: + results: + type: array + items: + $ref: '#/components/schemas/FileTag' + pages: + type: integer + description: Total number of pages + currentPage: + type: integer + description: Current page number '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '404': - description: File not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal server error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/NotFound' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] + - {} # Allows unauthenticated access to file tags - put: - summary: Replace image tag - description: Completely replace an image tag document + post: tags: - - Media (Built-in) + - Media + summary: Create file tag + description: Create a new file tag for organizing uploaded files (requires editor permissions or higher) + operationId: FileTagPost parameters: - - name: id - in: path - required: true - schema: - type: string - $ref: '#/components/parameters/AposMode' - $ref: '#/components/parameters/AposLocale' requestBody: @@ -3383,364 +8406,265 @@ paths: properties: title: type: string - slug: + description: File tag name + example: "Documents" + description: + type: string + description: Optional description of the file tag + example: "For organizing PDF documents and text files" + color: type: string + description: Color code for visual organization + pattern: "^#[0-9A-Fa-f]{6}$" + example: "#3498db" responses: '200': - description: Image tag updated + description: File tag created successfully content: application/json: schema: - $ref: '#/components/schemas/ImageTag' + $ref: '#/components/schemas/FileTag' '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' '404': - description: Image tag not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/NotFound' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - patch: - summary: Update image tag fields - description: Update specific fields of an image tag + /@apostrophecms/file-tag/archive: + post: tags: - - Media (Built-in) - parameters: - - name: id - in: path - required: true - schema: - type: string - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' + - Media + summary: Archive file tags + description: Archive multiple file tags, making them inactive while preserving their data + operationId: FileTagArchive requestBody: required: true content: application/json: schema: - type: object - properties: - title: - type: string - slug: - type: string - description: Only include fields to update + $ref: '#/components/schemas/BulkOperationRequest' responses: '200': - description: Image tag updated + description: File tags archived successfully content: application/json: schema: - $ref: '#/components/schemas/ImageTag' + type: array + items: + $ref: '#/components/schemas/FileTag' '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '404': - description: Image tag not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - delete: - summary: Delete image tag - description: Permanently delete an image tag + /@apostrophecms/file-tag/localize: + post: tags: - - Media (Built-in) - parameters: - - name: id - in: path - required: true - schema: - type: string - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' + - Media + summary: Localize file tags + description: Create or update localized versions of file tags for different languages/regions + operationId: FileTagLocalize + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + _ids: + type: array + items: + type: string + description: Array of file tag IDs to localize + toLocale: + type: string + description: Target locale for localization + example: "es" responses: '200': - description: Image tag deleted - '401': - description: Unauthorized + description: File tags localized successfully content: application/json: schema: - $ref: '#/components/schemas/Error' + type: array + items: + $ref: '#/components/schemas/FileTag' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '404': - description: Image tag not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - /@apostrophecms/image-tag/{id}/publish: + /@apostrophecms/file-tag/publish: post: - summary: Publish image tag draft - description: Publish the draft version of an image tag tags: - - Media (Built-in) - parameters: - - name: id - in: path - required: true - schema: - type: string - - $ref: '#/components/parameters/AposLocale' + - Media + summary: Publish file tags + description: Publish multiple file tags, making them live and visible to end users + operationId: FileTagPublish + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + _ids: + type: array + items: + type: string + description: Array of file tag IDs to publish responses: '200': - description: Image tag published + description: File tags published successfully content: application/json: schema: - $ref: '#/components/schemas/ImageTag' + type: array + items: + $ref: '#/components/schemas/FileTag' + '400': + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '404': - description: Image tag not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - /@apostrophecms/file-tag: - get: - summary: Get file tags - description: Retrieve file tags for organizing files + /@apostrophecms/file-tag/restore: + post: tags: - - Media (Built-in) - parameters: - - $ref: '#/components/parameters/Page' - - $ref: '#/components/parameters/PerPage' - - $ref: '#/components/parameters/Search' - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' - - $ref: '#/components/parameters/RenderAreas' + - Media + summary: Restore file tags + description: Restore previously archived file tags, making them active again + operationId: FileTagRestore + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BulkOperationRequest' responses: '200': - description: Successful response + description: File tags restored successfully content: application/json: schema: - allOf: - - $ref: '#/components/schemas/PaginatedResponse' - - type: object - properties: - results: - type: array - items: - $ref: '#/components/schemas/FileTag' + type: array + items: + $ref: '#/components/schemas/FileTag' '400': - description: Bad request - Invalid file ID format - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '404': - description: File not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' '500': - description: Internal server error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - - {} # Allows unauthenticated access if publicApiProjection is defined - post: - summary: Create file tag - description: Create a new file tag for organizing files + /@apostrophecms/file-tag/{_id}: + delete: tags: - - Media (Built-in) + - Media + summary: Delete file tag + description: Permanently delete a specific file tag by ID (requires appropriate permissions) + operationId: FileTagDeleteById parameters: - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' - requestBody: - required: true - content: - application/json: - schema: - type: object - required: - - title - properties: - title: - type: string - example: "Marketing Materials" - description: Tag name - slug: - type: string - example: "marketing-materials" - description: URL-friendly identifier (auto-generated if not provided) + - $ref: '#/components/parameters/DocumentId' responses: - '201': - description: File tag created successfully + '200': + description: File tag deleted successfully content: application/json: schema: $ref: '#/components/schemas/FileTag' '400': - description: Bad request - validation errors - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - /@apostrophecms/file-tag/{id}: get: - summary: Get single file tag - description: Retrieve a specific file tag by ID tags: - - Media (Built-in) + - Media + summary: Get file tag + description: Retrieve a specific file tag by ID + operationId: FileTagGetById parameters: - - name: id - in: path - required: true - description: File tag ID - schema: - type: string - example: "clx1234567890abcdef" + - $ref: '#/components/parameters/DocumentId' - $ref: '#/components/parameters/AposMode' - $ref: '#/components/parameters/AposLocale' - - $ref: '#/components/parameters/RenderAreas' responses: '200': - description: File tag found + description: File tag retrieved successfully content: application/json: schema: $ref: '#/components/schemas/FileTag' '400': - description: Bad request - Invalid file ID format - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' '404': - description: File not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/NotFound' '500': - description: Internal server error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - - {} # Allows unauthenticated access if publicApiProjection is defined + - {} # Allows unauthenticated access to file tags - put: - summary: Replace file tag - description: Completely replace a file tag document + patch: tags: - - Media (Built-in) + - Media + summary: Update file tag + description: Partially update a specific file tag by ID using PATCH semantics + operationId: FileTagPatchById parameters: - - name: id - in: path - required: true - schema: - type: string + - $ref: '#/components/parameters/DocumentId' - $ref: '#/components/parameters/AposMode' - $ref: '#/components/parameters/AposLocale' requestBody: @@ -3749,60 +8673,50 @@ paths: application/json: schema: type: object - required: - - title properties: title: type: string - slug: + description: File tag name + example: "Updated Documents" + description: type: string + description: Optional description of the file tag + example: "Updated description for organizing files" + color: + type: string + description: Color code for visual organization + pattern: "^#[0-9A-Fa-f]{6}$" + example: "#e74c3c" responses: '200': - description: File tag updated + description: File tag updated successfully content: application/json: schema: $ref: '#/components/schemas/FileTag' '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' '404': - description: File tag not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - patch: - summary: Update file tag fields - description: Update specific fields of a file tag + put: tags: - - Media (Built-in) + - Media + summary: Replace file tag + description: Completely replace a specific file tag by ID using PUT semantics + operationId: FileTagPutById parameters: - - name: id - in: path - required: true - schema: - type: string + - $ref: '#/components/parameters/DocumentId' - $ref: '#/components/parameters/AposMode' - $ref: '#/components/parameters/AposLocale' requestBody: @@ -3811,380 +8725,411 @@ paths: application/json: schema: type: object + required: + - title properties: title: type: string - slug: + description: File tag name + example: "Replaced Documents" + description: type: string - description: Only include fields to update + description: Optional description of the file tag + example: "Completely replaced file tag description" + color: + type: string + description: Color code for visual organization + pattern: "^#[0-9A-Fa-f]{6}$" + example: "#9b59b6" responses: '200': - description: File tag updated + description: File tag replaced successfully content: application/json: schema: $ref: '#/components/schemas/FileTag' '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' '404': - description: File tag not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - delete: - summary: Delete file tag - description: Permanently delete a file tag + /@apostrophecms/file-tag/{_id}/dismiss-submission: + post: tags: - - Media (Built-in) + - Media + summary: Dismiss file tag submission + description: Dismiss a pending submission for the specified file tag, removing it from the review queue + operationId: FileTagDismissSubmissionById parameters: - - name: id - in: path - required: true - schema: - type: string - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/DocumentId' responses: '200': - description: File tag deleted - '401': - description: Unauthorized + description: File tag submission dismissed successfully content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/schemas/FileTag' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' '404': - description: File tag not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - /@apostrophecms/file-tag/{id}/publish: - post: - summary: Publish file tag draft - description: Publish the draft version of a file tag + /@apostrophecms/file-tag/{_id}/locale/{toLocale}: + get: tags: - - Media (Built-in) + - Media + summary: Get file tag locale + description: Retrieve the specified file tag in a specific locale + operationId: FileTagGetLocaleById parameters: - - name: id - in: path - required: true - schema: - type: string - - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/DocumentId' + - $ref: '#/components/parameters/ToLocale' responses: '200': - description: File tag published + description: File tag locale retrieved successfully content: application/json: schema: $ref: '#/components/schemas/FileTag' + '400': + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' '404': - description: File tag not found + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/file-tag/{_id}/locales: + get: + tags: + - Media + summary: Get file tag locales + description: Retrieve all available locales for the specified file tag + operationId: FileTagGetLocalesById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: File tag locales retrieved successfully content: application/json: schema: - $ref: '#/components/schemas/Error' + type: array + items: + type: string + example: ["en", "es", "fr", "de"] + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - /@apostrophecms/attachment/upload: + /@apostrophecms/file-tag/{_id}/localize: post: - summary: Upload media file - description: | - Upload a media file to create an attachment. The uploaded file can then be used - to create image or file documents. Uses multipart/form-data encoding with the - file uploaded under the name 'file'. tags: - - Attachments (Built-in) + - Media + summary: Localize file tag + description: Create a localized version of the specified file tag for a specific language/region + operationId: FileTagLocalizeById parameters: - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/DocumentId' requestBody: required: true content: - multipart/form-data: + application/json: schema: type: object - required: - - file properties: - file: + toLocale: type: string - format: binary - description: The file to upload - encoding: - file: - contentType: image/*, application/pdf, application/*, text/* + description: Target locale for localization + example: "es" responses: '200': - description: File uploaded successfully + description: File tag localized successfully content: application/json: schema: - $ref: '#/components/schemas/Attachment' + $ref: '#/components/schemas/FileTag' '400': - description: Bad request - invalid file or missing file - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - authentication required - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '413': - description: File too large - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '415': - description: Unsupported file type + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/file-tag/{_id}/publish: + post: + tags: + - Media + summary: Publish file tag + description: Publish the specified file tag, making it live and visible to end users + operationId: FileTagPublishById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: File tag published successfully content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/schemas/FileTag' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - /@apostrophecms/attachment/crop: + /@apostrophecms/file-tag/{_id}/revert-draft-to-published: post: - summary: Crop image attachment - description: | - Create a cropped version of an existing image attachment. The crop object - is appended to the crops array property of the attachment document. - The newly uploaded image file will be stored with a filename using the - crop properties: {_id}-{name}.{top}.{left}.{width}.{height}.{extension} tags: - - Attachments (Built-in) + - Media + summary: Revert file tag draft to published + description: Revert the draft version of the specified file tag back to its published state + operationId: FileTagRevertDraftToPublishedById parameters: - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' - requestBody: - required: true - content: - application/json: - schema: - type: object - required: - - _id - - crop - properties: - _id: - type: string - description: The _id property of an existing image attachment document - example: "ckj0akbxa003vp39kfbxgb8zg" - crop: - type: object - description: Crop coordinates and dimensions - required: - - top - - left - - width - - height - properties: - top: - type: integer - description: Top coordinate of the crop area (pixels) - example: 10 - minimum: 0 - left: - type: integer - description: Left coordinate of the crop area (pixels) - example: 15 - minimum: 0 - width: - type: integer - description: Width of the crop area (pixels) - example: 300 - minimum: 1 - height: - type: integer - description: Height of the crop area (pixels) - example: 200 - minimum: 1 + - $ref: '#/components/parameters/DocumentId' responses: '200': - description: Image cropped successfully + description: File tag draft reverted to published successfully content: application/json: schema: - type: boolean - example: true - description: Returns true on successful crop + $ref: '#/components/schemas/FileTag' '400': - description: Bad request - invalid attachment ID or crop parameters + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/file-tag/{_id}/revert-published-to-previous: + post: + tags: + - Media + summary: Revert file tag published to previous + description: Revert the published version of the specified file tag to its previous published state + operationId: FileTagRevertPublishedToPreviousById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: File tag published version reverted to previous successfully content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/schemas/FileTag' + '400': + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - authentication required + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/file-tag/{_id}/share: + post: + tags: + - Media + summary: Share file tag + description: Generate a sharing link or configure sharing permissions for the specified file tag + operationId: FileTagShareById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: File tag shared successfully content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/schemas/FileTag' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' '404': - description: Attachment not found + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/file-tag/{_id}/submit: + post: + tags: + - Media + summary: Submit file tag + description: Submit the specified file tag for review and approval workflow + operationId: FileTagSubmitById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: File tag submitted successfully content: application/json: schema: - $ref: '#/components/schemas/Error' - '422': - description: Unprocessable entity - crop coordinates exceed image bounds + $ref: '#/components/schemas/FileTag' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/file-tag/{_id}/unpublish: + post: + tags: + - Media + summary: Unpublish file tag + description: Unpublish the specified file tag, removing it from public visibility while preserving the content + operationId: FileTagUnpublishById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: File tag unpublished successfully content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/schemas/FileTag' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - /article: + # Submitted-draft + /@apostrophecms/submitted-draft: get: - summary: Get articles - description: Retrieve blog articles (custom piece type) tags: - - Articles (Custom) + - Submitted Drafts + summary: List submitted drafts + description: Retrieve a list of all submitted drafts in the review queue + operationId: SubmittedDraftGet parameters: - - $ref: '#/components/parameters/Page' - - $ref: '#/components/parameters/PerPage' - - $ref: '#/components/parameters/Search' - $ref: '#/components/parameters/AposMode' - $ref: '#/components/parameters/AposLocale' - $ref: '#/components/parameters/RenderAreas' - # Custom query parameters for articles - - name: tags - in: query - description: Filter by article tags - schema: - type: array - items: - type: string - style: form - explode: true - example: ["cms", "tutorial"] - - name: _author - in: query - description: Filter by author ID - schema: - type: string - example: "clx1234567890abcdef" - - name: author - in: query - description: Filter by author slug - schema: - type: string - example: "john-doe" - - name: publishedAt - in: query - description: Filter by publication date - schema: - type: string - format: date - example: "2024-12-15" responses: '200': description: Successful response content: application/json: schema: - allOf: - - $ref: '#/components/schemas/PaginatedResponse' - - type: object - properties: - results: - type: array - items: - $ref: '#/components/schemas/Article' - '400': - description: Bad request - Invalid file ID format - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + type: object + properties: + results: + type: array + items: + $ref: '#/components/schemas/SubmittedDraft' + pages: + type: integer + description: Total number of pages available '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '404': - description: File not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal server error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - - {} # Allows unauthenticated access if publicApiProjection is defined post: - summary: Create article - description: Create a new blog article tags: - - Articles (Custom) + - Submitted Drafts + summary: Create submitted draft + description: Create a new submitted draft for review workflow (requires contributor permissions or higher) + operationId: SubmittedDraftPost parameters: - $ref: '#/components/parameters/AposMode' - $ref: '#/components/parameters/AposLocale' @@ -4194,223 +9139,285 @@ paths: application/json: schema: type: object - required: - - title properties: title: type: string - example: "Getting Started with Headless CMS" - slug: + description: Title of the submitted draft + example: "New Article Draft" + content: type: string - example: "getting-started-headless-cms" - description: Auto-generated from title if not provided - body: - type: object - description: Rich text content area - properties: - metaType: - type: string - example: "area" - items: - type: array - items: - type: object - description: Content widgets (rich text, images, etc.) - publishedAt: + description: Content of the submitted draft + example: "This is the draft content awaiting review." + author: type: string - format: date-time - description: Publication date - example: "2024-12-15T10:30:00.000Z" - tags: - type: array - items: - type: string - description: Article tags - example: ["cms", "headless", "tutorial"] - _author: - type: array - items: - type: string - description: Author IDs (relationship field) - example: ["clx1234567890abcdef"] - visibility: + description: Author of the submitted draft + example: "John Doe" + submissionNotes: + type: string + description: Notes from the submitter about the draft + example: "Please review for accuracy and tone." + priority: type: string - enum: ["public", "loginRequired"] - default: "public" + enum: [low, normal, high, urgent] + default: normal + description: Priority level for review + category: + type: string + description: Category or type of content being submitted + example: "blog-post" responses: - '201': - description: Article created successfully + '200': + description: Submitted draft created successfully content: application/json: schema: - $ref: '#/components/schemas/Article' + $ref: '#/components/schemas/SubmittedDraft' '400': - description: Bad request - validation errors + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + security: + - ApiKeyAuth: [] + - BearerAuth: [] + - SessionAuth: [] + + /@apostrophecms/submitted-draft/archive: + post: + tags: + - Submitted Drafts + summary: Archive submitted drafts + description: Archive multiple submitted drafts, removing them from active review queues while preserving data + operationId: SubmittedDraftArchive + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BulkOperationRequest' + responses: + '200': + description: Submitted drafts archived successfully content: application/json: schema: - $ref: '#/components/schemas/Error' + type: object + properties: + archived: + type: array + items: + $ref: '#/components/schemas/SubmittedDraft' + '400': + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + + /@apostrophecms/submitted-draft/localize: + post: + tags: + - Submitted Drafts + summary: Localize submitted drafts + description: Create or update localized versions of submitted drafts for different languages/regions + operationId: SubmittedDraftLocalize + responses: + '200': + description: Submitted drafts localized successfully content: application/json: schema: - $ref: '#/components/schemas/Error' - security: - - ApiKeyAuth: [] - - BearerAuth: [] - - SessionAuth: [] + type: object + properties: + localized: + type: array + items: + $ref: '#/components/schemas/SubmittedDraft' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' - /article/{id}: - get: - summary: Get single article - description: Retrieve a specific article by ID + /@apostrophecms/submitted-draft/publish: + post: + tags: + - Submitted Drafts + summary: Publish submitted drafts + description: Bulk publish multiple submitted drafts, moving them from draft status to published content + operationId: SubmittedDraftPublish + responses: + '200': + description: Submitted drafts published successfully + content: + application/json: + schema: + type: object + properties: + published: + type: array + items: + $ref: '#/components/schemas/SubmittedDraft' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + + /@apostrophecms/submitted-draft/restore: + post: + tags: + - Submitted Drafts + summary: Restore submitted drafts + description: Restore previously archived submitted drafts, returning them to active review queues + operationId: SubmittedDraftRestore + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BulkOperationRequest' + responses: + '200': + description: Submitted drafts restored successfully + content: + application/json: + schema: + type: object + properties: + restored: + type: array + items: + $ref: '#/components/schemas/SubmittedDraft' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + + /@apostrophecms/submitted-draft/{_id}: + delete: tags: - - Articles (Custom) + - Submitted Drafts + summary: Delete submitted draft + description: Permanently delete a specific submitted draft by ID (requires appropriate permissions) + operationId: SubmittedDraftDeleteById parameters: - - name: id - in: path - required: true - description: Article ID - schema: - type: string - example: "clx1234567890abcdef" - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' - - $ref: '#/components/parameters/RenderAreas' + - $ref: '#/components/parameters/DocumentId' responses: '200': - description: Article found + description: Submitted draft deleted successfully content: application/json: schema: - $ref: '#/components/schemas/Article' + $ref: '#/components/schemas/SubmittedDraft' '400': - description: Bad request - Invalid file ID format + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + + get: + tags: + - Submitted Drafts + summary: Get submitted draft + description: Retrieve a specific submitted draft by ID (requires appropriate permissions) + operationId: SubmittedDraftGetById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Submitted draft retrieved successfully content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/schemas/SubmittedDraft' + '400': + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' '404': - description: File not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/NotFound' '500': - description: Internal server error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - security: - - ApiKeyAuth: [] - - BearerAuth: [] - - SessionAuth: [] + $ref: '#/components/responses/InternalServerError' - put: - summary: Replace article - description: Completely replace an article document + patch: tags: - - Articles (Custom) + - Submitted Drafts + summary: Update submitted draft + description: Partially update a specific submitted draft by ID using PATCH semantics + operationId: SubmittedDraftPatchById parameters: - - name: id - in: path - required: true - schema: - type: string - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/DocumentId' requestBody: required: true content: application/json: schema: type: object - required: - - title properties: title: type: string - slug: + description: Updated title of the submitted draft + content: type: string - body: - type: object - publishedAt: + description: Updated content of the submitted draft + submissionNotes: type: string - format: date-time - tags: - type: array - items: - type: string - _author: - type: array - items: - type: string - visibility: + description: Updated notes about the submission + priority: type: string - enum: ["public", "loginRequired"] + enum: [low, normal, high, urgent] + description: Updated priority level for review responses: '200': - description: Article updated + description: Submitted draft updated successfully content: application/json: schema: - $ref: '#/components/schemas/Article' + $ref: '#/components/schemas/SubmittedDraft' '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' '404': - description: Article not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - patch: - summary: Update article fields - description: Update specific fields of an article + put: tags: - - Articles (Custom) + - Submitted Drafts + summary: Replace submitted draft + description: Completely replace a specific submitted draft by ID using PUT semantics + operationId: SubmittedDraftPutById parameters: - - name: id - in: path - required: true - schema: - type: string - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/DocumentId' requestBody: required: true content: @@ -4420,429 +9427,392 @@ paths: properties: title: type: string - slug: + description: Title of the submitted draft + example: "Updated Article Draft" + content: type: string - body: - type: object - publishedAt: + description: Content of the submitted draft + example: "This is the updated draft content." + author: type: string - format: date-time - tags: - type: array - items: - type: string - _author: - type: array - items: - type: string - visibility: + description: Author of the submitted draft + example: "John Doe" + submissionNotes: type: string - enum: ["public", "loginRequired"] - description: Only include fields to update + description: Notes about the submission + example: "Updated after initial feedback." + priority: + type: string + enum: [low, normal, high, urgent] + default: normal + description: Priority level for review + required: + - title + - content responses: '200': - description: Article updated + description: Submitted draft replaced successfully content: application/json: schema: - $ref: '#/components/schemas/Article' + $ref: '#/components/schemas/SubmittedDraft' '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' '404': - description: Article not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - security: - - ApiKeyAuth: [] - - BearerAuth: [] - - SessionAuth: [] + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' - delete: - summary: Delete article - description: Permanently delete an article + /@apostrophecms/submitted-draft/{_id}/dismiss-submission: + post: tags: - - Articles (Custom) + - Submitted Drafts + summary: Dismiss submission + description: Dismiss a pending submission for the specified draft, removing it from the review queue + operationId: SubmittedDraftDismissSubmissionById parameters: - - name: id - in: path - required: true - schema: - type: string - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/DocumentId' responses: '200': - description: Article deleted - '401': - description: Unauthorized + description: Submission dismissed successfully content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/schemas/SubmittedDraft' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' '404': - description: Article not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - security: - - ApiKeyAuth: [] - - BearerAuth: [] - - SessionAuth: [] + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' - /article/{id}/publish: - post: - summary: Publish article draft - description: Publish the draft version of an article + /@apostrophecms/submitted-draft/{_id}/locale/{toLocale}: + get: tags: - - Articles (Custom) + - Submitted Drafts + summary: Get submitted draft locale + description: Retrieve the specified submitted draft in a specific locale + operationId: SubmittedDraftGetLocaleById parameters: - - name: id - in: path - required: true - schema: - type: string - - $ref: '#/components/parameters/AposLocale' + - $ref: '#/components/parameters/DocumentId' + - $ref: '#/components/parameters/ToLocale' responses: '200': - description: Article published + description: Submitted draft locale retrieved successfully content: application/json: schema: - $ref: '#/components/schemas/Article' + $ref: '#/components/schemas/SubmittedDraft' + '400': + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' '404': - description: Article not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - security: - - ApiKeyAuth: [] - - BearerAuth: [] - - SessionAuth: [] + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' - /event: + /@apostrophecms/submitted-draft/{_id}/locales: get: - summary: Get events - description: Retrieve calendar events (custom piece type) tags: - - Events (Custom) + - Submitted Drafts + summary: Get submitted draft locales + description: Retrieve all available locales for the specified submitted draft + operationId: SubmittedDraftGetLocalesById parameters: - - $ref: '#/components/parameters/Page' - - $ref: '#/components/parameters/PerPage' - - $ref: '#/components/parameters/Search' - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' - - $ref: '#/components/parameters/RenderAreas' - # Custom query parameters for events - - name: startDate - in: query - description: Filter events by start date (exact match) - schema: - type: string - format: date - example: "2024-12-20" - - name: startDateFrom - in: query - description: Filter events starting from this date - schema: - type: string - format: date - example: "2024-12-01" - - name: startDateTo - in: query - description: Filter events starting before this date - schema: - type: string - format: date - example: "2024-12-31" - - name: location - in: query - description: Filter by event location - schema: - type: string - example: "Tech City" - - name: _image - in: query - description: Filter by image ID - schema: - type: string - example: "clx1234567890abcdef" + - $ref: '#/components/parameters/DocumentId' responses: '200': - description: Successful response + description: Submitted draft locales retrieved successfully content: application/json: schema: - allOf: - - $ref: '#/components/schemas/PaginatedResponse' - - type: object - properties: - results: - type: array - items: - $ref: '#/components/schemas/Event' + type: array + items: + type: string + example: ["en", "es", "fr", "de"] '400': - description: Bad request - Invalid file ID format - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Forbidden' '404': - description: File not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/NotFound' '500': - description: Internal server error + $ref: '#/components/responses/InternalServerError' + + /@apostrophecms/submitted-draft/{_id}/localize: + post: + tags: + - Submitted Drafts + summary: Localize submitted draft + description: Create a localized version of the specified submitted draft for a specific language/region + operationId: SubmittedDraftLocalizeById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Submitted draft localized successfully content: application/json: schema: - $ref: '#/components/schemas/Error' - security: - - ApiKeyAuth: [] - - BearerAuth: [] - - SessionAuth: [] - - {} # Allows unauthenticated access if publicApiProjection is defined + $ref: '#/components/schemas/SubmittedDraft' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + /@apostrophecms/submitted-draft/{_id}/publish: post: - summary: Create event - description: Create a new calendar event tags: - - Events (Custom) + - Submitted Drafts + summary: Publish submitted draft + description: Publish the specified submitted draft, moving it from draft status to published content + operationId: SubmittedDraftPublishById parameters: - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' - requestBody: - required: true - content: - application/json: - schema: - type: object - required: - - title - - startDate - properties: - title: - type: string - example: "ApostropheCMS Meetup" - slug: - type: string - example: "apostrophecms-meetup" - description: Auto-generated from title if not provided - description: - type: object - description: Rich text event description - startDate: - type: string - format: date-time - example: "2024-12-20T18:00:00.000Z" - endDate: - type: string - format: date-time - example: "2024-12-20T20:00:00.000Z" - location: - type: string - example: "123 Developer Street, Tech City" - _image: - type: array - items: - type: string - description: Event image IDs (relationship field) - example: ["clx1234567890abcdef"] - visibility: - type: string - enum: ["public", "loginRequired"] - default: "public" + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Submitted draft published successfully + content: + application/json: + schema: + $ref: '#/components/schemas/SubmittedDraft' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + + /@apostrophecms/submitted-draft/{_id}/revert-draft-to-published: + post: + tags: + - Submitted Drafts + summary: Revert draft to published + description: Revert the draft version of the specified submitted draft back to its published state + operationId: SubmittedDraftRevertDraftToPublishedById + parameters: + - $ref: '#/components/parameters/DocumentId' responses: - '201': - description: Event created successfully + '200': + description: Draft reverted to published successfully content: application/json: schema: - $ref: '#/components/schemas/Event' + $ref: '#/components/schemas/SubmittedDraft' '400': - description: Bad request - validation errors + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + + /@apostrophecms/submitted-draft/{_id}/revert-published-to-previous: + post: + tags: + - Submitted Drafts + summary: Revert published to previous + description: Revert the published version of the specified submitted draft to its previous published state + operationId: SubmittedDraftRevertPublishedToPreviousById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Published version reverted to previous successfully content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/schemas/SubmittedDraft' + '400': + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + + /@apostrophecms/submitted-draft/{_id}/share: + post: + tags: + - Submitted Drafts + summary: Share submitted draft + description: Generate a sharing link or configure sharing permissions for the specified submitted draft + operationId: SubmittedDraftShareById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Submitted draft shared successfully content: application/json: schema: - $ref: '#/components/schemas/Error' - security: - - ApiKeyAuth: [] - - BearerAuth: [] - - SessionAuth: [] + $ref: '#/components/schemas/SubmittedDraft' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' - /event/{id}: - get: - summary: Get single event - description: Retrieve a specific event by ID + /@apostrophecms/submitted-draft/{_id}/submit: + post: tags: - - Events (Custom) + - Submitted Drafts + summary: Submit draft + description: Submit the specified draft for review and approval workflow + operationId: SubmittedDraftSubmitById parameters: - - name: id - in: path - required: true - description: Event ID - schema: - type: string - example: "clx1234567890abcdef" - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' - - $ref: '#/components/parameters/RenderAreas' + - $ref: '#/components/parameters/DocumentId' responses: '200': - description: Event found + description: Draft submitted successfully content: application/json: schema: - $ref: '#/components/schemas/Event' + $ref: '#/components/schemas/SubmittedDraft' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' '404': - description: Event not found + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + + /@apostrophecms/submitted-draft/{_id}/unpublish: + post: + tags: + - Submitted Drafts + summary: Unpublish submitted draft + description: Unpublish the specified submitted draft, removing it from public visibility while preserving the content + operationId: SubmittedDraftUnpublishById + parameters: + - $ref: '#/components/parameters/DocumentId' + responses: + '200': + description: Submitted draft unpublished successfully content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/schemas/SubmittedDraft' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' - put: - summary: Replace event - description: Completely replace an event document + #Attachments + /@apostrophecms/attachment/upload: + post: tags: - - Events (Custom) + - Attachments + summary: Upload media file + description: | + Upload a media file to create an attachment. The uploaded file can then be used + to create image or file documents. Uses multipart/form-data encoding with the + file uploaded under the name 'file'. + operationId: AttachmentUpload parameters: - - name: id - in: path - required: true - schema: - type: string - $ref: '#/components/parameters/AposMode' - $ref: '#/components/parameters/AposLocale' requestBody: required: true content: - application/json: + multipart/form-data: schema: type: object required: - - title - - startDate + - file properties: - title: - type: string - slug: - type: string - description: - type: object - startDate: - type: string - format: date-time - endDate: - type: string - format: date-time - location: - type: string - _image: - type: array - items: - type: string - visibility: + file: type: string - enum: ["public", "loginRequired"] + format: binary + description: The file to upload + encoding: + file: + contentType: image/*, application/pdf, application/*, text/* responses: '200': - description: Event updated + description: File uploaded successfully content: application/json: schema: - $ref: '#/components/schemas/Event' + $ref: '#/components/schemas/Attachment' '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Forbidden + $ref: '#/components/responses/Unauthorized' + '413': + description: File too large content: application/json: schema: - $ref: '#/components/schemas/Error' - '404': - description: Event not found + $ref: '#/components/schemas/ApiError' + '415': + description: Unsupported file type content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/schemas/ApiError' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] - patch: - summary: Update event fields - description: Update specific fields of an event + /@apostrophecms/attachment/crop: + post: tags: - - Events (Custom) + - Attachments + summary: Crop image attachment + description: | + Create a cropped version of an existing image attachment. The crop object + is appended to the crops array property of the attachment document. + The newly uploaded image file will be stored with a filename using the + crop properties: {_id}-{name}.{top}.{left}.{width}.{height}.{extension} + operationId: AttachmentCrop parameters: - - name: id - in: path - required: true - schema: - type: string - $ref: '#/components/parameters/AposMode' - $ref: '#/components/parameters/AposLocale' requestBody: @@ -4851,141 +9821,72 @@ paths: application/json: schema: type: object + required: + - _id + - crop properties: - title: - type: string - slug: + _id: type: string - description: + description: The _id property of an existing image attachment document + example: "ckj0akbxa003vp39kfbxgb8zg" + crop: type: object - startDate: - type: string - format: date-time - endDate: - type: string - format: date-time - location: - type: string - _image: - type: array - items: - type: string - visibility: - type: string - enum: ["public", "loginRequired"] - description: Only include fields to update + description: Crop coordinates and dimensions + required: + - top + - left + - width + - height + properties: + top: + type: integer + description: Top coordinate of the crop area (pixels) + example: 10 + minimum: 0 + left: + type: integer + description: Left coordinate of the crop area (pixels) + example: 15 + minimum: 0 + width: + type: integer + description: Width of the crop area (pixels) + example: 300 + minimum: 1 + height: + type: integer + description: Height of the crop area (pixels) + example: 200 + minimum: 1 responses: '200': - description: Event updated + description: Image cropped successfully content: application/json: schema: - $ref: '#/components/schemas/Event' + type: boolean + example: true + description: Returns true on successful crop '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '404': - description: Event not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - security: - - ApiKeyAuth: [] - - BearerAuth: [] - - SessionAuth: [] - - delete: - summary: Delete event - description: Permanently delete an event - tags: - - Events (Custom) - parameters: - - name: id - in: path - required: true - schema: - type: string - - $ref: '#/components/parameters/AposMode' - - $ref: '#/components/parameters/AposLocale' - responses: - '200': - description: Event deleted - '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '404': - description: Event not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - security: - - ApiKeyAuth: [] - - BearerAuth: [] - - SessionAuth: [] - - /event/{id}/publish: - post: - summary: Publish event draft - description: Publish the draft version of an event - tags: - - Events (Custom) - parameters: - - name: id - in: path - required: true - schema: - type: string - - $ref: '#/components/parameters/AposLocale' - responses: - '200': - description: Event published - content: - application/json: - schema: - $ref: '#/components/schemas/Event' + $ref: '#/components/responses/BadRequest' '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/responses/Unauthorized' '404': - description: Event not found + $ref: '#/components/responses/NotFound' + '422': + description: Unprocessable entity - crop coordinates exceed image bounds content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/schemas/ApiError' + '500': + $ref: '#/components/responses/InternalServerError' security: - ApiKeyAuth: [] - BearerAuth: [] - SessionAuth: [] + # i18n /@apostrophecms/i18n/locales: get: tags: @@ -4994,6 +9895,7 @@ paths: description: | Returns information about all configured locales including labels and edit permissions. Authentication is required to access locale configuration data. + operationId: I18nLocalesGet responses: '200': description: Locales retrieved successfully @@ -5013,7 +9915,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/schemas/ApiError' '401': $ref: '#/components/responses/Unauthorized' '403': @@ -5023,7 +9925,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/schemas/ApiError' security: - ApiKeyAuth: [] - BearerAuth: [] @@ -5081,6 +9983,7 @@ paths: locale: "fr" contextDocId: "cloydg3ka0005qcls5vmg8sb9" clipboard: "exampleClipboardContent" + operationId: I18nLocalePost responses: '200': description: Locale path retrieved successfully @@ -5108,6 +10011,7 @@ paths: security: - ApiKeyAuth: [] - BearerAuth: [] + - SessionAuth: [] /@apostrophecms/i18n/exist-in-locale: post: @@ -5152,6 +10056,7 @@ paths: ids: ["cloydg3ka0005qcls5vmg8sb9", "cloydg3ka0005qcls5vmg8sb8"] locale: "fr" mode: "published" + operationId: I18nExistsPost responses: '200': description: Document existence check completed successfully diff --git a/docs/reference/api/sandbox.md b/docs/reference/api/sandbox.md index 3e1776b9..85c81271 100644 --- a/docs/reference/api/sandbox.md +++ b/docs/reference/api/sandbox.md @@ -6,15 +6,159 @@ description: Interactive OpenAPI documentation for ApostropheCMS REST API # Interactive API Reference > **💡 Sandbox Testing**: This online explorer can connect to a project running at `localhost:3000` on your workstation to test standard API routes. You can test with API key or bearer token authentication, but not session cookies. +> + +## Before you start + +To use this page as an API sandbox: + +1. **Start your Apostrophe project** + + ```bash + npm run dev + # or + node app + ``` + + Make sure it is reachable at: + + - `http://localhost:3000` (default ApostropheCMS dev port) + +2. **Scroll to the server URL in the spec** + + In the sidebar, the [`Interactive Explorer`](/reference/api/sandbox.html#🔽-interactive-explorer) is marked with an icon. In the Swagger UI, you will find the **Server** dropdown near the top. It should show something like: + + - `http://localhost:3000` + +3. **Click the `Authorize` button** + - See more below about authorization steps. +--- + +## Step-by-step: Authorize and run your first request + +Swagger UI will happily send anonymous requests, but most Apostrophe endpoints require authentication. + +Follow these steps carefully: + +1. **Click the green “Authorize” button** + +2. **Choose an auth method** + + The dialog lists three security schemes. + + - `ApiKeyAuth` + - `BearerAuth` + - `SessionAuth` + +3. **Recommended: start with API key auth** + + - In your project, typically in the `modules/@apostrophecms/express/index.js` file, add an API key: + ``` js + export default { + options: { + session: { + secret: 'myProjectSecret' + }, + apiKeys: { + mysecretapikey: { + role: 'admin' + } + } + } + }; + ``` + - In the **Authorize** dialog of the explorer, scroll up to find the **API key** entry. + - Paste your API key into the value field - in this example, `mysecretapikey`. + - Click **Authorize**. + - Then click **Close** at the bottom of the dialog. + > [!NOTE] + > You will not get any message regarding the validity of the key. If your endpoint requests fail with a `404` error, you likely entered the key wrong. Logout from the API key authorization section and reenter the key. + +4. **Try a simple GET request** + ![The 'Get Users' GET endpoint in the Swagger UI](../../images/swagger-user-endpoint.png) + + - Expand a simple GET endpoint (for example, the first “Users” route). + - Click the route to expand it + - Click **Try it out** + - Change any of the parameters if desired + - Click **Execute** + - Check the **Response** section below the request: + - Status `200` or `201` = success + - Status `401`, `403` or `404` = auth problem; double-check your API key. + +--- + +## Alternative: Bearer token via login route (more steps) + +If you prefer to log in with a username/password instead of using an API key, you can: + +1. **Find the login route** +![The Swagger UI POST login route endpoint selector](../../images/swagger-login-route.png) + - In the explorer, look for the login endpoint (`POST` with `/@apostrophecms/login/login`). + - Expand that operation. + +2. **Send a login request** + + - Click **Try it out**. + - In the request body, edit the `username` and `password` values. + - Click **Execute**. + +3. **Copy the token from the response** + + - In the **Responses**, scroll down to the `200` response. + - Manually copy the token value, not including the quotes. The copy button will copy both the key and value. + +4. **Configure Bearer auth in Swagger UI** + + - Click the **Authorize** button at the top of the Swagger UI. + - Find the **BearerAuth** input. + - Paste **only** the token value into the field (Swagger UI will add `Bearer ` for you). + - Click **Authorize**, then **Close**. + +5. **Try a simple GET request** + ![The 'Get Users' GET endpoint in the Swagger UI](../../images/swagger-user-endpoint.png) + + - Expand a simple GET endpoint (for example, the first “Users” route). + - Click the route to expand it + - Click **Try it out** + - Change any of the parameters if desired + - Click **Execute** + - Check the **Response** section below the request: + - Status `200` or `201` = success + - Status `401`, `403` or `404` = auth problem; double-check your token. + +--- + +## Why session cookie auth is not supported here + +ApostropheCMS typically uses a session cookie (for example, `project-shortname.sid`) when you log into the admin UI. The online Swagger explorer **cannot** reuse that login, because: + +- The in-documentation Swagger UI runs in your browser as a separate web app. +- It cannot safely or portably access cookies from another origin. +- Even if it could, CORS rules usually block cross-site cookie usage. + +Because of this, you **cannot** use the "Authorize" dialog to test “I’m logged into the admin UI” style session behavior. For cookie-based flows: + +- Download the [OpenAPI spec file repo](https://github.com/apostrophecms/apostrophecms-openapi) and set it up locally +- Use an API client like Postman/Insomnia and configure cookie handling there. + +The interactive explorer on this page is intentionally focused on **header-based authentication**: API keys and bearer tokens. + +--- + +## 🔽 Interactive Explorer + +Below is the full Swagger UI. +Once your server is running and you follow the authorization instructions, use `Try it out → Execute` in each endpoint to test. To take this farther, jump below the [explorer](#testing-against-your-own-site). ## Testing Against Your Own Site -1. **Download**: Get our [OpenAPI specification](/openapi.yaml){download="apostrophecms-openapi.yaml"} -2. **Import**: Load it into Postman, Insomnia, or similar tools +1. **Download**: Get our [OpenAPI specification](/openapi.yaml){download="apostrophecms-openapi.yaml"} or the [full repo](https://github.com/apostrophecms/apostrophecms-openapi). +2. **Import**: Load it into Postman, Insomnia, or similar tools if not using the repo 3. **Configure**: Set your server URL and authentication token - - Server URL (change `https://your-site.com` to your actual domain) + - Server URL (change `https://your-site.com` to your actual domain) - Session cookie name (change `project-shortname.sid` to `yourproject.sid`) 4. **Test**: Make live API calls to your ApostropheCMS instance, either locally or your hosted site @@ -28,5 +172,7 @@ This interactive documentation is generated from our [OpenAPI specification](/ap - **Understand schemas**: Explore all data models and field requirements - **Copy code samples**: Get ready-to-use code +For more guidance, see our [`apostrophecms-openapi` repo](https://github.com/apostrophecms/apostrophecms-openapi). + ## Start learning about the ApostropheCMS API [Learn more about API authentication →](/reference/api/authentication) diff --git a/package-lock.json b/package-lock.json index 39b4c693..5308746b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "jsdom": "^22.1.0", "marked": "^12.0.2", "socket.io-client": "^4.7.5", - "swagger-ui-dist": "^5.22.0", + "swagger-ui-dist": "^5.30.3", "uuid": "^10.0.0", "vitepress-plugin-pagefind": "^0.2.4", "vue": "^3.3.4", @@ -4506,15 +4506,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fuse.js": { - "version": "6.6.2", - "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-6.6.2.tgz", - "integrity": "sha512-cJaJkxCCxC8qIIcPBF9yGxY0W/tVZS3uEISDxhYIdtk8OL93pe+6Zj7LjCqVV4dzbqcriOZ+kQ/NE4RXZHsIGA==", - "license": "Apache-2.0", - "engines": { - "node": ">=10" - } - }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -8402,9 +8393,9 @@ "dev": true }, "node_modules/swagger-ui-dist": { - "version": "5.24.1", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.24.1.tgz", - "integrity": "sha512-ITeWc7CCAfK53u8jnV39UNqStQZjSt+bVYtJHsOEL3vVj/WV9/8HmsF8Ej4oD8r+Xk1HpWyeW/t59r1QNeAcUQ==", + "version": "5.30.3", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.30.3.tgz", + "integrity": "sha512-giQl7/ToPxCqnUAx2wpnSnDNGZtGzw1LyUw6ZitIpTmdrvpxKFY/94v1hihm0zYNpgp1/VY0jTDk//R0BBgnRQ==", "license": "Apache-2.0", "dependencies": { "@scarf/scarf": "=1.4.0" @@ -8687,15 +8678,6 @@ "node": ">=20.18.1" } }, - "node_modules/undici-types": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", - "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/unicorn-magic": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", @@ -9055,18 +9037,6 @@ "@types/mdurl": "*" } }, - "node_modules/vitepress/node_modules/@types/node": { - "version": "24.0.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.1.tgz", - "integrity": "sha512-MX4Zioh39chHlDJbKmEgydJDS3tspMP/lnQC67G3SWsTnb9NeYVWOjkxpOSy4oMfPs4StcWHwBrvUb4ybfnuaw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "undici-types": "~7.8.0" - } - }, "node_modules/vitepress/node_modules/@vitejs/plugin-vue": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", @@ -9172,6 +9142,15 @@ "nanoid": "^4.0.0" } }, + "node_modules/vue-command-palette/node_modules/fuse.js": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-6.6.2.tgz", + "integrity": "sha512-cJaJkxCCxC8qIIcPBF9yGxY0W/tVZS3uEISDxhYIdtk8OL93pe+6Zj7LjCqVV4dzbqcriOZ+kQ/NE4RXZHsIGA==", + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, "node_modules/vue-command-palette/node_modules/nanoid": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.2.tgz", diff --git a/package.json b/package.json index 9406ecf2..22d2d7be 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "jsdom": "^22.1.0", "marked": "^12.0.2", "socket.io-client": "^4.7.5", - "swagger-ui-dist": "^5.22.0", + "swagger-ui-dist": "^5.30.3", "uuid": "^10.0.0", "vitepress-plugin-pagefind": "^0.2.4", "vue": "^3.3.4", From a83e764b7c690c88e0118cfa31c0b6a32856aa18 Mon Sep 17 00:00:00 2001 From: Robert Means Date: Tue, 9 Dec 2025 13:35:02 -0500 Subject: [PATCH 8/8] Rearrange and update API reference --- docs/.vitepress/sidebarGuide.js | 3 +- docs/reference/api/api-explorer.md | 320 +++++++++++++++-------- docs/reference/api/rest-api-reference.md | 209 +++++++++++++++ docs/reference/api/sandbox.md | 178 ------------- 4 files changed, 417 insertions(+), 293 deletions(-) create mode 100644 docs/reference/api/rest-api-reference.md delete mode 100644 docs/reference/api/sandbox.md diff --git a/docs/.vitepress/sidebarGuide.js b/docs/.vitepress/sidebarGuide.js index e35b50bf..7f51b671 100644 --- a/docs/.vitepress/sidebarGuide.js +++ b/docs/.vitepress/sidebarGuide.js @@ -222,7 +222,8 @@ const sidebarGuide = [ icon: 'brain-circuit', text: 'REST API Reference', collapsed: true, - items: getItemRefs(['README'], '', 'reference', 'api') + link: 'reference/api/rest-api-reference.md', + items: getItemRefs(['README', 'rest-api-reference'], '', 'reference', 'api') }, { icon: 'open-book', diff --git a/docs/reference/api/api-explorer.md b/docs/reference/api/api-explorer.md index a35a0a0a..c90969be 100644 --- a/docs/reference/api/api-explorer.md +++ b/docs/reference/api/api-explorer.md @@ -1,117 +1,209 @@ --- -title: ApostropheCMS API Documentation -description: Complete REST API reference for ApostropheCMS headless CMS +title: ApostropheCMS API Explorer - Interactive Testing +description: Test ApostropheCMS REST API endpoints interactively with live authentication --- -# ApostropheCMS REST API OpenAPI Specification - -ApostropheCMS provides a comprehensive REST API for headless CMS functionality, perfect for agencies managing multiple client sites. - -## What is the ApostropheCMS API? - -The ApostropheCMS API is a RESTful interface that allows developers to: -- Create and manage content programmatically -- Build headless applications with any frontend framework -- Integrate with third-party services and tools -- Manage multisite configurations for agency workflows - -## OpenAPI Specification - -Our API follows OpenAPI 3.0 standards, making it compatible with modern development tools and AI assistants. - -### What is OpenAPI? -OpenAPI (formerly Swagger) is a standardized way to describe REST APIs. Our specification includes: -- All available endpoints and methods -- Request/response schemas and examples -- Authentication requirements -- Error codes and responses - -### Downloads -- [OpenAPI YAML Specification](/apostrophecms-openapi.yaml){download="apostrophecms-openapi.yaml"} - -## How to Use This Specification - -### For Developers -- **Import into Postman**: Use our spec to auto-generate API collections -- **Generate client libraries**: Create SDKs for JavaScript, Python, PHP, etc. -- **API exploration**: Browse all endpoints interactively in our [sandbox](/reference/api/sandbox) - -### For AI Integration -Our OpenAPI spec enables: -- **ChatGPT plugins**: Compatible with OpenAI's plugin system -- **Documentation chatbots**: Use with RAG systems for automated API support -- **Code generation**: AI coding tools can generate accurate ApostropheCMS API code - -[Continue to the API Sandbox →](/reference/api/sandbox) or start learning more: - - - - - - - - - - - - - - - - \ No newline at end of file +# API Explorer + +The API Explorer lets you test ApostropheCMS REST API endpoints directly in your browser with real authentication. Connect to your local development server or a live instance to experiment with requests and see actual responses. + +## When to Use the Explorer vs Documentation + +**Use the API Explorer when you want to:** +- Test endpoints with your actual project data +- Experiment with query parameters and request bodies +- Validate authentication configuration +- Generate curl commands for debugging +- Quickly verify an endpoint's behavior + +**Use the [written API documentation](rest-api-reference) when you want to:** +- Learn API patterns and best practices +- Understand field formats and data structures +- Copy code examples into your application +- Read detailed explanations of endpoints +- Work offline or on mobile + +> **💡 Testing with Localhost**: This explorer can connect to a project running at `localhost:3000` on your workstation to test standard API routes. You can test with API key or bearer token authentication, but not session cookies. + +--- + +## Before you start + +To use this page as an interactive testing environment: + +1. **Start your Apostrophe project** + + ```bash + npm run dev + # or + node app + ``` + + Make sure it is reachable at: + + - `http://localhost:3000` (default ApostropheCMS dev port) + +2. **Scroll to the server URL in the spec** + + In the sidebar, the [`Interactive Explorer`](#📽-interactive-explorer) is marked with an icon. In the Swagger UI, you will find the **Server** dropdown near the top. It should show something like: + + - `http://localhost:3000` + +3. **Click the `Authorize` button** + - See more below about authorization steps. +--- + +## Step-by-step: Authorize and run your first request + +Swagger UI will happily send anonymous requests, but most Apostrophe endpoints require authentication. + +Follow these steps carefully: + +1. **Click the green "Authorize" button** + +2. **Choose an auth method** + + The dialog lists three security schemes. + + - `ApiKeyAuth` + - `BearerAuth` + - `SessionAuth` + +3. **Recommended: start with API key auth** + + - In your project, typically in the `modules/@apostrophecms/express/index.js` file, add an API key: + ``` js + export default { + options: { + session: { + secret: 'myProjectSecret' + }, + apiKeys: { + mysecretapikey: { + role: 'admin' + } + } + } + }; + ``` + - In the **Authorize** dialog of the explorer, scroll up to find the **API key** entry. + - Paste your API key into the value field - in this example, `mysecretapikey`. + - Click **Authorize**. + - Then click **Close** at the bottom of the dialog. + > [!NOTE] + > You will not get any message regarding the validity of the key. If your endpoint requests fail with a `404` error, you likely entered the key wrong. Logout from the API key authorization section and reenter the key. + +4. **Try a simple GET request** + ![The 'Get Users' GET endpoint in the Swagger UI](../../images/swagger-user-endpoint.png) + + - Expand a simple GET endpoint (for example, the first "Users" route). + - Click the route to expand it + - Click **Try it out** + - Change any of the parameters if desired + - Click **Execute** + - Check the **Response** section below the request: + - Status `200` or `201` = success + - Status `401`, `403` or `404` = auth problem; double-check your API key. + +--- + +## Alternative: Bearer token via login route (more steps) + +If you prefer to log in with a username/password instead of using an API key, you can: + +1. **Find the login route** +![The Swagger UI POST login route endpoint selector](../../images/swagger-login-route.png) + - In the explorer, look for the login endpoint (`POST` with `/@apostrophecms/login/login`). + - Expand that operation. + +2. **Send a login request** + + - Click **Try it out**. + - In the request body, edit the `username` and `password` values. + - Click **Execute**. + +3. **Copy the token from the response** + + - In the **Responses**, scroll down to the `200` response. + - Manually copy the token value, not including the quotes. The copy button will copy both the key and value. + +4. **Configure Bearer auth in Swagger UI** + + - Click the **Authorize** button at the top of the Swagger UI. + - Find the **BearerAuth** input. + - Paste **only** the token value into the field (Swagger UI will add `Bearer ` for you). + - Click **Authorize**, then **Close**. + +5. **Try a simple GET request** + ![The 'Get Users' GET endpoint in the Swagger UI](../../images/swagger-user-endpoint.png) + + - Expand a simple GET endpoint (for example, the first "Users" route). + - Click the route to expand it + - Click **Try it out** + - Change any of the parameters if desired + - Click **Execute** + - Check the **Response** section below the request: + - Status `200` or `201` = success + - Status `401`, `403` or `404` = auth problem; double-check your token. + +--- + +## Why session cookie auth is not supported here + +ApostropheCMS typically uses a session cookie (for example, `project-shortname.sid`) when you log into the admin UI. The online Swagger explorer **cannot** reuse that login, because: + +- The in-documentation Swagger UI runs in your browser as a separate web app. +- It cannot safely or portably access cookies from another origin. +- Even if it could, CORS rules usually block cross-site cookie usage. + +Because of this, you **cannot** use the "Authorize" dialog to test "I'm logged into the admin UI" style session behavior. For cookie-based flows: + +- Download the [OpenAPI spec file repo](https://github.com/apostrophecms/apostrophecms-openapi) and set it up locally +- Use an API client like Postman/Insomnia and configure cookie handling there. + +The interactive explorer on this page is intentionally focused on **header-based authentication**: API keys and bearer tokens. + +--- + +## 📽 Interactive Explorer + +Below is the full Swagger UI. +Once your server is running and you follow the authorization instructions, use `Try it out → Execute` in each endpoint to test. + + + +--- + +## Need More Detail? + +The API Explorer shows you what each endpoint does, but for deeper understanding: + +- **[API Documentation Home](/reference/api/rest-api-reference)** - Overview and getting started +- **[Authentication Guide](/reference/api/authentication)** - Detailed auth setup +- **[Piece Type API](/reference/api/pieces)** - Working with content types +- **[Page Type API](/reference/api/pages)** - Managing pages and navigation +- **[Field Formats](/reference/api/field-formats)** - Understanding response structures + +--- + +## Testing Against Your Own Site + +For testing against deployed sites or more advanced workflows: + +1. **Download**: Get our [OpenAPI specification](/openapi.yaml){download="apostrophecms-openapi.yaml"} or the [full repo](https://github.com/apostrophecms/apostrophecms-openapi). +2. **Import**: Load it into Postman, Insomnia, or similar tools if not using the repo +3. **Configure**: Set your server URL and authentication token + - Server URL (change `https://your-site.com` to your actual domain) + - Session cookie name (change `project-shortname.sid` to `yourproject.sid`) +4. **Test**: Make live API calls to your ApostropheCMS instance, either locally or your hosted site + +## About This Reference + +This interactive documentation is generated from our [OpenAPI specification](/apostrophecms-openapi.yaml). You can: + +- **Test endpoints live**: Make real API calls to your locally running project (with authentication) +- **View request/response examples**: See exactly what data to send and expect +- **Understand schemas**: Explore all data models and field requirements +- **Copy code samples**: Get ready-to-use code + +For more guidance, see our [`apostrophecms-openapi` repo](https://github.com/apostrophecms/apostrophecms-openapi). \ No newline at end of file diff --git a/docs/reference/api/rest-api-reference.md b/docs/reference/api/rest-api-reference.md new file mode 100644 index 00000000..0dc22408 --- /dev/null +++ b/docs/reference/api/rest-api-reference.md @@ -0,0 +1,209 @@ +--- +title: ApostropheCMS REST API Reference +description: Complete REST API documentation for ApostropheCMS headless CMS +next: + text: 'Authentication' + link: '/reference/api/authentication.html' +--- + +# ApostropheCMS REST API + +ApostropheCMS provides a comprehensive REST API for headless CMS functionality, enabling you to build modern applications with any frontend framework while managing content through Apostrophe's intuitive editing experience. + +## Getting Started + +The REST API gives you programmatic access to all your content and media: + +- **Content Management**: Create, read, update, and delete pages and pieces +- **Media Operations**: Upload, crop, and organize images and files +- **Multilingual Support**: Manage content across multiple locales +- **Flexible Authentication**: API keys for server-to-server, bearer tokens for client apps + +### Quick Start + +All API endpoints follow RESTful conventions and return JSON responses. Most operations require authentication: + +```javascript +// Example: Fetch published articles +const response = await fetch('https://example.net/api/v1/article', { + headers: { + 'Authorization': 'Bearer your-token-here' + } +}); +const articles = await response.json(); +``` + +## Core API Documentation + + + + + + +### Content APIs + + + + + + + + + + + +### Internationalization + + + + + +## How to Use This Documentation + +This REST API reference provides two complementary ways to work with the ApostropheCMS API: + +### Written Documentation (This Section) + +The guides on this page and in the navigation are your comprehensive reference for understanding the API: + +- **Learn patterns and concepts** with explanations and context +- **Copy production-ready code** examples into your application +- **Understand field formats** with detailed examples +- **Read offline or on mobile** when you need it + +Start here if you're new to the API or building an integration. + +### API Explorer (Interactive Testing) + +Once you understand the basics, use the API Explorer to test endpoints with your own data: + +- **Test live requests** against your local or deployed ApostropheCMS instance +- **Experiment with parameters** and see real-time responses +- **Validate your authentication** setup before writing code +- **Generate curl commands** for quick testing + +[Open the API Explorer →](api-explorer) + +> **Tip**: The written documentation and API Explorer show the same endpoints - use the written docs to learn, then the Explorer to test. + +### OpenAPI Specification + +For advanced workflows, download our complete OpenAPI 3.0 specification: + +- Import into Postman, Insomnia, or other API clients +- Generate client libraries in any language +- Integrate with AI coding assistants +- Build custom tooling and automation + +[Download OpenAPI Spec](/apostrophecms-openapi.yaml){download="apostrophecms-openapi.yaml"} + +## Common Patterns + +### Querying Content + +Retrieve published content with pagination and filtering: + +```javascript +const response = await fetch( + 'https://example.net/api/v1/article?page=1&perPage=10', + { + headers: { 'Authorization': 'Bearer your-token' } + } +); +``` + +### Creating Documents + +Post new content with required fields: + +```javascript +const response = await fetch('https://example.net/api/v1/article', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer your-token' + }, + body: JSON.stringify({ + title: 'My New Article', + slug: 'my-new-article' + }) +}); +``` + +### Working with Locales + +Access content in specific locales using the `aposLocale` query parameter: + +```javascript +const response = await fetch( + 'https://example.net/api/v1/article?aposLocale=fr', + { + headers: { 'Authorization': 'Bearer your-token' } + } +); +``` + +## Need Help? + +- **Stack Overflow**: Tag questions with `apostrophe-cms` +- **Discord**: Join our [community chat](https://chat.apostrophecms.com) +- **GitHub**: Report issues or contribute at [apostrophecms/apostrophe](https://github.com/apostrophecms/apostrophe) + +Ready to start building? Check out the [authentication guide](/reference/api/authentication) to set up your first API request. + diff --git a/docs/reference/api/sandbox.md b/docs/reference/api/sandbox.md deleted file mode 100644 index 85c81271..00000000 --- a/docs/reference/api/sandbox.md +++ /dev/null @@ -1,178 +0,0 @@ ---- -title: ApostropheCMS API Reference - Interactive Explorer -description: Interactive OpenAPI documentation for ApostropheCMS REST API ---- - -# Interactive API Reference - -> **💡 Sandbox Testing**: This online explorer can connect to a project running at `localhost:3000` on your workstation to test standard API routes. You can test with API key or bearer token authentication, but not session cookies. -> - -## Before you start - -To use this page as an API sandbox: - -1. **Start your Apostrophe project** - - ```bash - npm run dev - # or - node app - ``` - - Make sure it is reachable at: - - - `http://localhost:3000` (default ApostropheCMS dev port) - -2. **Scroll to the server URL in the spec** - - In the sidebar, the [`Interactive Explorer`](/reference/api/sandbox.html#🔽-interactive-explorer) is marked with an icon. In the Swagger UI, you will find the **Server** dropdown near the top. It should show something like: - - - `http://localhost:3000` - -3. **Click the `Authorize` button** - - See more below about authorization steps. ---- - -## Step-by-step: Authorize and run your first request - -Swagger UI will happily send anonymous requests, but most Apostrophe endpoints require authentication. - -Follow these steps carefully: - -1. **Click the green “Authorize” button** - -2. **Choose an auth method** - - The dialog lists three security schemes. - - - `ApiKeyAuth` - - `BearerAuth` - - `SessionAuth` - -3. **Recommended: start with API key auth** - - - In your project, typically in the `modules/@apostrophecms/express/index.js` file, add an API key: - ``` js - export default { - options: { - session: { - secret: 'myProjectSecret' - }, - apiKeys: { - mysecretapikey: { - role: 'admin' - } - } - } - }; - ``` - - In the **Authorize** dialog of the explorer, scroll up to find the **API key** entry. - - Paste your API key into the value field - in this example, `mysecretapikey`. - - Click **Authorize**. - - Then click **Close** at the bottom of the dialog. - > [!NOTE] - > You will not get any message regarding the validity of the key. If your endpoint requests fail with a `404` error, you likely entered the key wrong. Logout from the API key authorization section and reenter the key. - -4. **Try a simple GET request** - ![The 'Get Users' GET endpoint in the Swagger UI](../../images/swagger-user-endpoint.png) - - - Expand a simple GET endpoint (for example, the first “Users” route). - - Click the route to expand it - - Click **Try it out** - - Change any of the parameters if desired - - Click **Execute** - - Check the **Response** section below the request: - - Status `200` or `201` = success - - Status `401`, `403` or `404` = auth problem; double-check your API key. - ---- - -## Alternative: Bearer token via login route (more steps) - -If you prefer to log in with a username/password instead of using an API key, you can: - -1. **Find the login route** -![The Swagger UI POST login route endpoint selector](../../images/swagger-login-route.png) - - In the explorer, look for the login endpoint (`POST` with `/@apostrophecms/login/login`). - - Expand that operation. - -2. **Send a login request** - - - Click **Try it out**. - - In the request body, edit the `username` and `password` values. - - Click **Execute**. - -3. **Copy the token from the response** - - - In the **Responses**, scroll down to the `200` response. - - Manually copy the token value, not including the quotes. The copy button will copy both the key and value. - -4. **Configure Bearer auth in Swagger UI** - - - Click the **Authorize** button at the top of the Swagger UI. - - Find the **BearerAuth** input. - - Paste **only** the token value into the field (Swagger UI will add `Bearer ` for you). - - Click **Authorize**, then **Close**. - -5. **Try a simple GET request** - ![The 'Get Users' GET endpoint in the Swagger UI](../../images/swagger-user-endpoint.png) - - - Expand a simple GET endpoint (for example, the first “Users” route). - - Click the route to expand it - - Click **Try it out** - - Change any of the parameters if desired - - Click **Execute** - - Check the **Response** section below the request: - - Status `200` or `201` = success - - Status `401`, `403` or `404` = auth problem; double-check your token. - ---- - -## Why session cookie auth is not supported here - -ApostropheCMS typically uses a session cookie (for example, `project-shortname.sid`) when you log into the admin UI. The online Swagger explorer **cannot** reuse that login, because: - -- The in-documentation Swagger UI runs in your browser as a separate web app. -- It cannot safely or portably access cookies from another origin. -- Even if it could, CORS rules usually block cross-site cookie usage. - -Because of this, you **cannot** use the "Authorize" dialog to test “I’m logged into the admin UI” style session behavior. For cookie-based flows: - -- Download the [OpenAPI spec file repo](https://github.com/apostrophecms/apostrophecms-openapi) and set it up locally -- Use an API client like Postman/Insomnia and configure cookie handling there. - -The interactive explorer on this page is intentionally focused on **header-based authentication**: API keys and bearer tokens. - ---- - -## 🔽 Interactive Explorer - -Below is the full Swagger UI. -Once your server is running and you follow the authorization instructions, use `Try it out → Execute` in each endpoint to test. To take this farther, jump below the [explorer](#testing-against-your-own-site). - - - -## Testing Against Your Own Site - -1. **Download**: Get our [OpenAPI specification](/openapi.yaml){download="apostrophecms-openapi.yaml"} or the [full repo](https://github.com/apostrophecms/apostrophecms-openapi). -2. **Import**: Load it into Postman, Insomnia, or similar tools if not using the repo -3. **Configure**: Set your server URL and authentication token - - Server URL (change `https://your-site.com` to your actual domain) - - Session cookie name (change `project-shortname.sid` to `yourproject.sid`) -4. **Test**: Make live API calls to your ApostropheCMS instance, either locally or your hosted site - - -## About This Reference - -This interactive documentation is generated from our [OpenAPI specification](/apostrophecms-openapi.yaml). You can: - -- **Test endpoints live**: Make real API calls to your locally running project (with authentication) -- **View request/response examples**: See exactly what data to send and expect -- **Understand schemas**: Explore all data models and field requirements -- **Copy code samples**: Get ready-to-use code - -For more guidance, see our [`apostrophecms-openapi` repo](https://github.com/apostrophecms/apostrophecms-openapi). - -## Start learning about the ApostropheCMS API -[Learn more about API authentication →](/reference/api/authentication)