9.0.0-beta.4
Pre-release@comet/admin@9.0.0-beta.4
Minor Changes
-
d7b77af: Add
ErrorHandlerProvideranduseErrorHandlerfor centralized error reporting fromErrorBoundaryErrorBoundarynow invokes an optionalonError(error, errorInfo)callback provided throughErrorHandlerProvider's context whenever it catches an error. The visible Alert UI ofErrorBoundaryis unchanged — the callback is purely additive and intended for forwarding errors to a reporting service (e.g., Sentry).Example
import { ErrorHandlerProvider } from "@comet/admin"; <ErrorHandlerProvider onError={(error, errorInfo) => { // Report the error to your error tracking service console.error(error, errorInfo.componentStack); }} > {children} </ErrorHandlerProvider>;
-
2fe9d4b: Add support for translating page and document content
Content translation can now be applied to entire documents at once, in addition to the existing field-level translation.
Setup
Wrap the application with
AzureAiTranslatorProvider(supportsbatchTranslateautomatically):<AzureAiTranslatorProvider enabled showApplyTranslationDialog> {children} </AzureAiTranslatorProvider>
Making a document type translatable
Add
createDocumentTranslationMethodsand theTranslatableInterfacetype to the document definition:import { createDocumentTranslationMethods, type TranslatableInterface } from "@comet/cms-admin"; const rootBlocks = { content: PageContentBlock, seo: SeoBlock, }; export const Page: DocumentInterface & TranslatableInterface & DependencyInterface = { // ...existing config ...createDocumentRootBlocksMethods(rootBlocks), ...createDocumentTranslationMethods(rootBlocks), };
Adding translate action to the edit page
createUsePagenow returns atranslateContentfunction. Use it withTranslateContentMenuIteminside aCrudMoreActionsMenu:const { translateContent /* ...other fields */ } = usePage({ pageId: id }); <CrudMoreActionsMenu overallActions={[<TranslateContentMenuItem translateContent={translateContent} />]} />;
Page tree integration
The page tree context menu and bulk action toolbar automatically show a "Translate" action for pages. This translates the page name, slug, and document content.
-
460cbfb: Add translation support for textarea fields in
FinalFormInputPreviously, only
type="text"fields supported content translation. Nowtype="textarea"fields (used byTextAreaField) also show the translate button and use a multiline translation dialog.
Patch Changes
-
8e40458: Fix
Stackcrash when location changes before any breadcrumb is registeredStackaccessed the last entry of an empty breadcrumb array on location change, causing aTypeError: Cannot set properties of undefined. Guarded the update to skip when no breadcrumbs are registered yet.
@comet/admin-rte@9.0.0-beta.4
Minor Changes
-
2fe9d4b: Add support for translating page and document content
Content translation can now be applied to entire documents at once, in addition to the existing field-level translation.
Setup
Wrap the application with
AzureAiTranslatorProvider(supportsbatchTranslateautomatically):<AzureAiTranslatorProvider enabled showApplyTranslationDialog> {children} </AzureAiTranslatorProvider>
Making a document type translatable
Add
createDocumentTranslationMethodsand theTranslatableInterfacetype to the document definition:import { createDocumentTranslationMethods, type TranslatableInterface } from "@comet/cms-admin"; const rootBlocks = { content: PageContentBlock, seo: SeoBlock, }; export const Page: DocumentInterface & TranslatableInterface & DependencyInterface = { // ...existing config ...createDocumentRootBlocksMethods(rootBlocks), ...createDocumentTranslationMethods(rootBlocks), };
Adding translate action to the edit page
createUsePagenow returns atranslateContentfunction. Use it withTranslateContentMenuIteminside aCrudMoreActionsMenu:const { translateContent /* ...other fields */ } = usePage({ pageId: id }); <CrudMoreActionsMenu overallActions={[<TranslateContentMenuItem translateContent={translateContent} />]} />;
Page tree integration
The page tree context menu and bulk action toolbar automatically show a "Translate" action for pages. This translates the page name, slug, and document content.
@comet/cms-admin@9.0.0-beta.4
Minor Changes
-
d7b77af: Add
onErrortoCometConfigfor centralized error reporting from all error boundariesCometConfigProvidernow accepts an optionalonError(error, errorInfo)callback that is invoked whenever any descendantErrorBoundarycatches an error. Use this to forward errors to a reporting service such as Sentry.Example
<CometConfigProvider {...config} onError={(error, errorInfo) => { // Report the error to your error tracking service console.error(error, errorInfo.componentStack); }} > {children} </CometConfigProvider>
-
c6703db: Export
ChooseDamFilesDialogAllows building custom multi-file picker UIs on top of the DAM file dialog (e.g. bulk-adding files to a list block).
import { ChooseDamFilesDialog } from "@comet/cms-admin"; <ChooseDamFilesDialog open={open} onClose={onClose} onConfirm={(fileIds) => ...} initialFileIds={[]} allowedMimetypes={["image/jpeg"]} />
-
127a492: Add TipTapRichTextBlock as an alternative to RichTextBlock
-
c6703db: Add
multipleprop toFileFieldfor selecting multiple DAM filesFileFieldnow acceptsmultiple={true}to select a list of DAM files instead of a single file. Multi-file values are typed asGQLDamFileFieldFileFragment[](the same fragment used in single-file mode); the component renders a stacked list of files with per-row menu and remove actions. The picker dialog pre-checks the current selection viainitialFileIdsand returns the picked file ids on confirm. The single-file API is unchanged.Example
<Field name="files" component={FileField} multiple preview={(file) => <Thumbnail fileId={file.id} />} />
-
2fe9d4b: Add support for translating page and document content
Content translation can now be applied to entire documents at once, in addition to the existing field-level translation.
Setup
Wrap the application with
AzureAiTranslatorProvider(supportsbatchTranslateautomatically):<AzureAiTranslatorProvider enabled showApplyTranslationDialog> {children} </AzureAiTranslatorProvider>
Making a document type translatable
Add
createDocumentTranslationMethodsand theTranslatableInterfacetype to the document definition:import { createDocumentTranslationMethods, type TranslatableInterface } from "@comet/cms-admin"; const rootBlocks = { content: PageContentBlock, seo: SeoBlock, }; export const Page: DocumentInterface & TranslatableInterface & DependencyInterface = { // ...existing config ...createDocumentRootBlocksMethods(rootBlocks), ...createDocumentTranslationMethods(rootBlocks), };
Adding translate action to the edit page
createUsePagenow returns atranslateContentfunction. Use it withTranslateContentMenuIteminside aCrudMoreActionsMenu:const { translateContent /* ...other fields */ } = usePage({ pageId: id }); <CrudMoreActionsMenu overallActions={[<TranslateContentMenuItem translateContent={translateContent} />]} />;
Page tree integration
The page tree context menu and bulk action toolbar automatically show a "Translate" action for pages. This translates the page name, slug, and document content.
Patch Changes
-
fa5c7a4: Fix
FileFieldbreaking image block selectionThe
DamFileFieldFilefragment lost the image dimensions (width,height,cropArea) needed byDamImageBlock/PixelImageBlock. Selecting an image inside an image block crashed because those fields were missing. Restored them on the fragment.Composing the fragment into a parent collection (e.g. a many-to-many to
DamFile) exposed a Mikro-ORM gotcha:Collection.loadItems()does not honoreager: true, so each loadedDamFilehad an uninitializedimageReference and GraphQL threwCannot return null for non-nullable field DamFileImage.width. Added animage@ResolveFieldonFilesResolverthat initializes the Reference if needed, so consumers don't have to remember to populate it. -
31d9296: Fix duplicate TipTap
'link'extension warning by explicitly disabling StarterKit's built-in Link extensionStarterKit (v3+) includes
@tiptap/extension-linkby default. Since we register our ownCmsLinkmark (also named"link"), this caused a "Duplicate extension names found: ['link']" warning. Settinglink: falseinStarterKit.configure()resolves this. -
ae85ba9: Fix
TipTapRichTextBlocktoolbar colors to match the existingRichTextBlocktoolbarThe TipTap toolbar incorrectly used Comet's
greyPalette(wheregreyPalette[100]is#D9D9D9) for the toolbar background, button icon, hover, and disabled states. This made the toolbar look noticeably darker than the existing Draft.js-basedRichTextBlocktoolbar, which uses MUI's lightergreypalette (grey[100]is#F5F5F5). The TipTap toolbar now uses the same MUI grey shades for these states so the two toolbars look consistent. -
ab5e547: Validate the SEO block's structured data field as JSON
The structured data field in the SEO block now shows a validation error when the entered value is not valid JSON. This matches the existing API-side
@IsJSON()validation and prevents invalid payloads from being saved.
@comet/api-generator@9.0.0-beta.4
Patch Changes
-
16c0e64: Fix missing import for nested
ManyToOneresolver target entities@comet/api-generatornow imports nestedManyToOnetarget entities in generated resolvers so generated code compiles without unresolved symbol errors.
@comet/cms-api@9.0.0-beta.4
Minor Changes
-
c6703db: Add
idsfilter todamFilesListFileFilterInputnow accepts an optionalids: [ID!]to restrict the result set to specific files. Useful for batch-loading a known selection (e.g. after a multi-file picker confirms) in a single request. -
127a492: Add TipTapRichTextBlock as an alternative to RichTextBlock
-
2fe9d4b: Add support for translating page and document content
Content translation can now be applied to entire documents at once, in addition to the existing field-level translation.
Setup
Wrap the application with
AzureAiTranslatorProvider(supportsbatchTranslateautomatically):<AzureAiTranslatorProvider enabled showApplyTranslationDialog> {children} </AzureAiTranslatorProvider>
Making a document type translatable
Add
createDocumentTranslationMethodsand theTranslatableInterfacetype to the document definition:import { createDocumentTranslationMethods, type TranslatableInterface } from "@comet/cms-admin"; const rootBlocks = { content: PageContentBlock, seo: SeoBlock, }; export const Page: DocumentInterface & TranslatableInterface & DependencyInterface = { // ...existing config ...createDocumentRootBlocksMethods(rootBlocks), ...createDocumentTranslationMethods(rootBlocks), };
Adding translate action to the edit page
createUsePagenow returns atranslateContentfunction. Use it withTranslateContentMenuIteminside aCrudMoreActionsMenu:const { translateContent /* ...other fields */ } = usePage({ pageId: id }); <CrudMoreActionsMenu overallActions={[<TranslateContentMenuItem translateContent={translateContent} />]} />;
Page tree integration
The page tree context menu and bulk action toolbar automatically show a "Translate" action for pages. This translates the page name, slug, and document content.
Patch Changes
-
fa5c7a4: Fix
FileFieldbreaking image block selectionThe
DamFileFieldFilefragment lost the image dimensions (width,height,cropArea) needed byDamImageBlock/PixelImageBlock. Selecting an image inside an image block crashed because those fields were missing. Restored them on the fragment.Composing the fragment into a parent collection (e.g. a many-to-many to
DamFile) exposed a Mikro-ORM gotcha:Collection.loadItems()does not honoreager: true, so each loadedDamFilehad an uninitializedimageReference and GraphQL threwCannot return null for non-nullable field DamFileImage.width. Added animage@ResolveFieldonFilesResolverthat initializes the Reference if needed, so consumers don't have to remember to populate it. -
31d9296: Fix duplicate TipTap
'link'extension warning by explicitly disabling StarterKit's built-in Link extensionStarterKit (v3+) includes
@tiptap/extension-linkby default. Since we register our ownCmsLinkmark (also named"link"), this caused a "Duplicate extension names found: ['link']" warning. Settinglink: falseinStarterKit.configure()resolves this.
@comet/cli@9.0.0-beta.4
Major Changes
-
2529907: Replace
install-agent-skillswithinstall-agent-features— a combined installer for agent skills and agent rulesinstall-agent-featuresinstalls skills fromskills/<name>/SKILL.mdandagentic-plugin/skills/<name>/SKILL.md(folders) and rules fromrules/<name>.md(single markdown files) — both from the local repo and from external git repos listed inagent-features.json. Skills install into.agents/skills/and.claude/skills/; rules install into.agents/rules/,.claude/rules/,.cursor/rules/, and.github/instructions/so they are picked up by Claude Code, Cursor, GitHub Copilot, and other cloud agents. Rules support the same optionalmetadata.internal: truefrontmatter as skills, and may be organized into subdirectories (the layout is preserved in each target).Example
agent-features.json:{ "repos": ["https://github.com/vivid-planet/comet.git"] }Run:
npx @comet/cli install-agent-features
Breaking change: the
install-agent-skillscommand and itsagent-skills.jsonconfig are removed. Migrate by renamingagent-skills.jsontoagent-features.json(the schema is identical) and replacing theinstall-agent-skillsinvocation inpackage.jsonandinstall.shwithinstall-agent-features.
@comet/eslint-config@9.0.0-beta.4
Major Changes
-
695a9c9: Promote
future/*ESLint rules into the main configsThe rules previously only available via
@comet/eslint-config/future/*are now part of the main configs and apply by default. Thefuture/*subpaths are kept as aliases that re-export the main configs, so existing imports continue to work without changes.Newly active rules in the main configs
react.js:react/jsx-no-literals(with a small allowlist of common symbols)@typescript-eslint/consistent-type-exportsformatjs/enforce-default-messageis now enforced as"literal"
nextjs.js:node-cacheis restricted viano-restricted-imports
nestjs.js:node-cacheis restricted viano-restricted-imports(andrestrictedImportPathsis now exported)
@comet/mail-react@9.0.0-beta.4
Minor Changes
-
0cc1b06: Add config context with
Config,ConfigProvider, anduseConfigConfigis an augmentable interface for runtime configuration — intended for environment-specific data. Add custom keys via TypeScript interface declaration merging:declare module "@comet/mail-react" { interface Config { myKey?: { foo: string }; } }
Define the config using the
configprop onMjmlMailRootor by mountingConfigProviderdirectly. Use theuseConfighook to read the value. -
ba777cf: Add
HtmlPixelImageBlockandMjmlPixelImageBlockfor rendering Comet CMSPixelImageBlockDatain emailsConfigure
MjmlMailRoot.config.pixelImageBlockonce with the API's allowed image sizes and base URL; the blocks resolve the render width and build the image URL.Pass
aspectRatio(e.g."16x9") to override the DAM crop ratio.<MjmlMailRoot config={{ pixelImageBlock: { validSizes: [...cometConfig.images.imageSizes, ...cometConfig.images.deviceSizes], baseUrl: process.env.API_URL, }, }} > <MjmlPixelImageBlock data={pixelImageData} width={536} /> </MjmlMailRoot>
-
a7bb900: Add
headandattributesprops toMjmlMailRoot-
head—ReactNodeappended inside<MjmlHead>after the registered styles block. -
attributes—ReactNodeappended inside<MjmlAttributes>after the default<MjmlAll>.<MjmlMailRoot attributes={<MjmlClass name="link" color="blue" />} head={<MjmlFont name="Foo" href="https://example.com/foo.css" />}> {/* email body */} </MjmlMailRoot>
-
@comet/site-nextjs@9.0.0-beta.4
Major Changes
-
8b3932d: Move server-only exports to
/serversubpathServer-only exports have been moved to a separate
/serverentry point to prevent server-only code from being pulled into client bundles. While tree-shaking previously removed unused server code, this is an optional optimization — Vite's dev server, for example, does not tree-shake, causing errors when importing these packages in non-server environments (e.g., Storybook).@comet/site-nextjs:sitePreviewRoute,legacyPagesRouterSitePreviewApiHandler,previewParams,legacyPagesRouterPreviewParams, andpersistedQueryRoutemust now be imported from@comet/site-nextjs/server:- import { sitePreviewRoute } from "@comet/site-nextjs"; + import { sitePreviewRoute } from "@comet/site-nextjs/server";
- import { previewParams } from "@comet/site-nextjs"; + import { previewParams } from "@comet/site-nextjs/server";
- import { persistedQueryRoute } from "@comet/site-nextjs"; + import { persistedQueryRoute } from "@comet/site-nextjs/server";
@comet/site-react:persistedQueryRoutemust now be imported from@comet/site-react/server:- import { persistedQueryRoute } from "@comet/site-react"; + import { persistedQueryRoute } from "@comet/site-react/server";
Minor Changes
-
ab5e547: Add
JsonLdcomponent for typed schema.org structured dataRenders any
schema-dtsentity inside a<script type="application/ld+json">tag. The payload is escaped so a</script>sequence in user content cannot break out of the script tag.import { JsonLd } from "@comet/site-react"; import type { Organization } from "schema-dts"; <JsonLd<Organization> data={{ "@context": "https://schema.org", "@type": "Organization", name: "Acme", url: "https://acme.example", logo: "https://acme.example/logo.png", }} />;
Also re-exported from
@comet/site-nextjs.
Patch Changes
-
b7daf28: Fix
PixelImageBlockandImagefailing to render in Next.js Pages Router withError: Element type is invalid ... but got: object@comet/site-nextjsis published as ESM ("type": "module") and the components used a default import ofnext/image(CJS). Under Next.js Pages Router the server bundler keeps node_modules ESM packages as Node-style externals, which applies Node-style ESM↔CJS interop:import NextImage from "next/image"yields the entire module-namespace object ({ default, getImageProps, __esModule: true }) instead of the component. The default import is now unwrapped at module evaluation time so the components work under both bundler-style and Node-style interop.
@comet/site-react@9.0.0-beta.4
Major Changes
-
8b3932d: Move server-only exports to
/serversubpathServer-only exports have been moved to a separate
/serverentry point to prevent server-only code from being pulled into client bundles. While tree-shaking previously removed unused server code, this is an optional optimization — Vite's dev server, for example, does not tree-shake, causing errors when importing these packages in non-server environments (e.g., Storybook).@comet/site-nextjs:sitePreviewRoute,legacyPagesRouterSitePreviewApiHandler,previewParams,legacyPagesRouterPreviewParams, andpersistedQueryRoutemust now be imported from@comet/site-nextjs/server:- import { sitePreviewRoute } from "@comet/site-nextjs"; + import { sitePreviewRoute } from "@comet/site-nextjs/server";
- import { previewParams } from "@comet/site-nextjs"; + import { previewParams } from "@comet/site-nextjs/server";
- import { persistedQueryRoute } from "@comet/site-nextjs"; + import { persistedQueryRoute } from "@comet/site-nextjs/server";
@comet/site-react:persistedQueryRoutemust now be imported from@comet/site-react/server:- import { persistedQueryRoute } from "@comet/site-react"; + import { persistedQueryRoute } from "@comet/site-react/server";
Minor Changes
-
ab5e547: Add
JsonLdcomponent for typed schema.org structured dataRenders any
schema-dtsentity inside a<script type="application/ld+json">tag. The payload is escaped so a</script>sequence in user content cannot break out of the script tag.import { JsonLd } from "@comet/site-react"; import type { Organization } from "schema-dts"; <JsonLd<Organization> data={{ "@context": "https://schema.org", "@type": "Organization", name: "Acme", url: "https://acme.example", logo: "https://acme.example/logo.png", }} />;
Also re-exported from
@comet/site-nextjs.