9.0.0-beta.6
Pre-release@comet/admin@9.0.0-beta.6
Minor Changes
-
15e771b: Add
TimeRangePickerandTimeRangePickerFieldcomponentsThese MUI X-based components complete the set of date/time components in
@comet/adminand replace the deprecatedTimeRangePicker,TimeRangeFieldandFinalFormTimeRangePickerfrom@comet/admin-date-time.The
valueand the value passed toonChangeare aTimeRangeobject withstartandendas 24-hour time strings (HH:mm):type TimeRange = { start: string | null; end: string | null; };
Patch Changes
-
b4ba869: Fix Data Grid Excel export for
singleSelectcolumnsWhen a
singleSelectcolumn usesvalueOptions, Excel export now resolves the exported cell value to the matching option label unless a customvalueFormatteroverrides it. -
57678d0: Fix
FinalFormNumberInputdirtying the form on mount when the initial value isnullThe value-sync effect inside
FinalFormNumberInputran on mount and calledinput.onChange(undefined)wheneverinput.valuewas empty. For a form whose initial value wasnull, this silently normalized the value toundefined, making the fielddirtybefore any user interaction and breaking dirty-tracking features such asEditDialog,SaveBoundary, and the unsaved-changes router prompt.The mount-time sync now only updates the formatted display string. The empty-input normalization to
undefinedstill happens on real user interaction inhandleBlur. -
b459ec7: Reduce published package size by keeping non-runtime build artifacts out of the bundle
@comet/admin-date-time@9.0.0-beta.6
Major Changes
-
15e771b: Deprecate
TimeRangePicker,TimeRangeFieldandFinalFormTimeRangePickerand add a "Legacy" prefix to their class-names and theme component-keyTheir new counterparts in
@comet/adminare now considered stable.Consider using the new components from
@comet/adminIn most cases, the new components will be a drop-in replacement for the legacy components, so you can simply replace the imports:
| Legacy component from
@comet/admin-date-time| New component from@comet/admin|
| ---------------------------------------------- | -------------------------------------------------- |
|TimeRangePicker|TimeRangePicker|
|TimeRangeField|TimeRangePickerField|
|FinalFormTimeRangePicker|TimeRangePickerField(without using<Field />) |To continue using the existing component, the following changes will need to be made:
Update any use of class-names of the component's slots:
-
CometAdminTimeRangePicker-*->CometAdminLegacyTimeRangePicker-*Update the component-key when using
defaultPropsorstyleOverridesin the theme: -
CometAdminTimeRangePicker->CometAdminLegacyTimeRangePicker
-
Minor Changes
-
1a83c01: Deprecate the
@comet/admin-date-timepackageAll of its components now have stable replacements in
@comet/admin. The remaining exports (DatePickerNavigation,DateFnsLocaleProvider,DateFnsLocaleContextanduseDateFnsLocale) are now marked as deprecated as well.See the migration guide for how to migrate to the new components in
@comet/admin.
@comet/brevo-admin@9.0.0-beta.6
Patch Changes
-
51f25f1: Fix
BrevoContactFormsendingsendDoubleOptInin update mutationsendDoubleOptInis not a valid field ofBrevoContactUpdateInputand only applies when creating a contact. The field was being included in the update payload because it was initialized in form state but not stripped out before the update mutation was called.
@comet/cms-admin@9.0.0-beta.6
Minor Changes
-
4c1aeb2: Add
noFollowoption toExternalLinkBlockEditors can now mark an external link as
nofollowvia a new checkbox in the admin form. When enabled, the rendered<a>tag receivesrel="nofollow". Existing links are unaffected by an automatic block-data migration that setsnoFollowtofalse. -
7fbe2a7: Add
allowPageDeleteoption to disable deletion of pages in the PageTree. When set tofalse, the delete option is hidden in the Admin UI and the API blocks deletion attempts. -
7ab96c2: Add
SearchHeaderItemcomponent for full-text searchThe
SearchHeaderItemcomponent renders a search input (intended for the header) that opens a dropdown with the results of themyFullTextSearchquery. The search is restricted to the currently selected content scope. Clicking a result opens the corresponding entity using theentityDependencyMapfrom theDependenciesConfig(the same mechanism used by warnings and dependencies).Example
import { Header, SearchHeaderItem } from "@comet/cms-admin"; <Header> <SearchHeaderItem /> <ContentScopeControls /> <UserHeaderItem /> </Header>;
Patch Changes
-
0e9189b: Export
AnonymousBlockInterfacetype -
c7f80e9: Fix page search not expanding the tree when navigating between matches after "Collapse all"
Previously, jumping to the next or previous search match only scrolled to the match without expanding its collapsed ancestors. After collapsing the tree via "Collapse all" during an active search, continuing the search revealed nothing. Navigating between matches now re-expands the current match's ancestors before scrolling to it.
-
b459ec7: Reduce published package size by keeping non-runtime build artifacts out of the bundle
-
5e87236: Remove pagination from
StartBuildsDialogdata gridThe
buildTemplatesquery always returns all templates, so the page-based pagination in the dialog grid was misleading. All templates are now displayed at once.
@comet/api-generator@9.0.0-beta.6
Minor Changes
-
70a77db: Reuse
@RequiredPermissionfrom entity in resolver permissionsThe
UserPermissionsGuardnow falls back to the entity's@RequiredPermissiondecorator when no permission is explicitly set on the resolver. The entity is resolved from the@Resolver(() => Entity)decorator.Additionally, the CRUD generator no longer emits
@RequiredPermissionon generated resolvers if the entity already has@RequiredPermissionset. This avoids redundant permission declarations.
@comet/brevo-api@9.0.0-beta.6
Major Changes
-
f932845: Update
@getbrevo/brevoto v5The transactional mail service's
sendmethod now accepts aSendTransacEmailRequest(withoutsender) instead of aSendSmtpEmail. The commonly used fields (to,subject,htmlContent,textContent) are unchanged, so existing calls continue to work.
@comet/cms-api@9.0.0-beta.6
Minor Changes
-
f1a473a: Allow
AffectedScopeto return multiple scopesThe
argsToScopefunction can now returnContentScope[]in addition to a singleContentScope. When multiple scopes are returned, the user must have access to all of them (AND relationship).@AffectedScope((args: MyArgs) => [{ domain: args.fromDomain }, { domain: args.toDomain }])
-
8954d64: Add
findUser/findUserOrThrow(andfindUserForLogin/findUserForLoginOrThrow) toUserPermissionsUserServiceInterfaceThe throwing
getUserandgetUserForLoginmethods onUserPermissionsUserServiceInterfaceare now deprecated in favor of paired find methods:-
findUser(id): Promise<User | null>/findUserOrThrow(id): Promise<User> -
findUserForLogin(id): Promise<User | null>/findUserForLoginOrThrow(id): Promise<User>This lets consumers opt into a non-throwing path without wrapping lookups in
try/catch. Existing implementations that only definegetUser/getUserForLogincontinue to work; the service falls back to them.Example
export class UserService implements UserPermissionsUserServiceInterface { async findUser(id: string): Promise<User | null> { return this.users.find((user) => user.id === id) ?? null; } async findUserOrThrow(id: string): Promise<User> { const user = await this.findUser(id); if (!user) { throw new Error(`User not found: ${id}`); } return user; } // ... }
-
-
4c1aeb2: Add
noFollowoption toExternalLinkBlockEditors can now mark an external link as
nofollowvia a new checkbox in the admin form. When enabled, the rendered<a>tag receivesrel="nofollow". Existing links are unaffected by an automatic block-data migration that setsnoFollowtofalse. -
67938b2: Filter
myFullTextSearchresults by the entity's required permissionThe
requiredPermissionof an entity (declared via the@RequiredPermissiondecorator) is now included in both theEntityInfoandEntityInfoFullTextSQL views.The
myFullTextSearchquery (formerlyfullTextSearch) filters results based on the current user's permissions, only returning entities where the user has the required permission. Entries without a required permission are excluded from results, as the permission cannot be determined. Themyprefix reflects that the query operates on the current user and only returns entities the user is allowed to see.Example usage:
@EntityInfo<Product>({ name: "title", secondaryInformation: "category.name", visible: { status: { $eq: ProductStatus.Published } }, fullText: "fullText", }) @RequiredPermission("products") @ObjectType() @Entity() export class Product { // ... }
-
7fbe2a7: Add
allowPageDeleteoption to disable deletion of pages in the PageTree. When set tofalse, the delete option is hidden in the Admin UI and the API blocks deletion attempts. -
1b37655: Add scope support to
myFullTextSearchThe
EntityInfoFullTextview now includes ascopescolumn, and themyFullTextSearchquery accepts an optionalscopeargument to restrict results to a single content scope.The scopes are derived from either a
scopeproperty on the entity (simple case) or the@ScopedEntitydecorator. To support building the scopes in SQL,@ScopedEntityaccepts a new declarative, SQL-convertible variant in addition to the existing callback/service:// Field path to the scope object (an embeddable) @ScopedEntity("company.scope") // Object mapping scope properties to field paths @ScopedEntity({ companyId: "company.id" }) // Multiple scopes @ScopedEntity(["company.scope", "otherCompany.scope"])
The existing callback and service variants keep working everywhere
@ScopedEntityis used (e.g. the auth guard). They cannot be converted to SQL, so an entity that is part of the full-text index must use the declarative variant (or have ascopeproperty) — otherwise creating theEntityInfoFullTextview throws. -
70a77db: Reuse
@RequiredPermissionfrom entity in resolver permissionsThe
UserPermissionsGuardnow falls back to the entity's@RequiredPermissiondecorator when no permission is explicitly set on the resolver. The entity is resolved from the@Resolver(() => Entity)decorator.Additionally, the CRUD generator no longer emits
@RequiredPermissionon generated resolvers if the entity already has@RequiredPermissionset. This avoids redundant permission declarations. -
8498a7c: Export
EntityInfoObject,EntityInfoFullTextObjectandPaginatedEntityInfoThis allows building custom full-text search resolvers (for example a public, permission-independent site search) that reuse the existing full-text search views and re-use the
entityInforelation to return name and secondary information.
Patch Changes
-
35e9e0d: Fix copying the home page creating a second page with the slug
homePreviously, copying the home page produced a second page with the slug
home, after which none of the home pages could be deleted (deleting a page with the slughomeis forbidden). The copy now receives a different slug if the target scope already has a home page, and keepshomeonly when there is none yet. -
91f4a9f: Fix DAM file listing failing for files larger than ~2 GB
The
sizefield ofDamFileandFileUploadwas exposed as a GraphQLInt, which can only represent 32-bit signed integers (max ~2.1 GB). Files exceeding this size (e.g. large videos) caused the GraphQL response to fail withInt cannot represent non 32-bit signed integer value, breaking the DAM file list and the "Select files from DAM" dialog. The field is now exposed asBigInt, which represents the full range of file sizes stored in the database (bigint). -
affbb11: Load
jsdomlazily for SVG validationjsdom(~90 MB resident) was imported and instantiated at module load time, so importing anything from@comet/cms-apipulled it into memory even when no SVG was ever validated. It's now loaded on the first SVG validation instead, reducing the package's base memory footprint. -
fad0167: Load
@kubernetes/client-nodelazily inKubernetesService@kubernetes/client-node(~85 MB resident) was statically imported, so importing anything from@comet/cms-apipulled it into memory even for projects that don't use the Kubernetes-based builds feature. The runtime parts of the client are now required lazily whenKubernetesServiceactually connects to a cluster, reducing the package's base memory footprint. -
6793853: Load
openailazily inAzureOpenAiContentGenerationServiceThe
openaiclient was statically imported, so importing anything from@comet/cms-apipulled it into memory even when the content-generation feature was disabled. It's now required lazily when a client is actually created, reducing the package's base memory footprint. -
ac59b62: Validate uploaded SVGs with
DOMPurify(backed byjsdom) instead of the custom XML-based checkThe previous implementation parsed SVGs with
fast-xml-parserand applied a hand-written allow/deny list to reject scripts, event handlers and unsafe links.
SVGs are now sanitized with the vettedDOMPurifylibrary and rejected when it has to strip any tags or attributes, providing more robust protection against XSS vectors in uploaded SVGs.The
roleattribute and the<use>element are allowed, since they're commonly used in valid SVGs.<use>is restricted to same-document fragment references (e.g.href="#id"); references to external resources are rejected to prevent XSS/SSRF.
@comet/cli@9.0.0-beta.6
Patch Changes
- b459ec7: Reduce published package size by keeping non-runtime build artifacts out of the bundle
@comet/mail-react@9.0.0-beta.6
Minor Changes
-
124d889: Add theme support to
MjmlButtonand add a newHtmlButtoncomponentMjmlButtonnow supports theme-based styling throughtheme.button, an optionalvariantprop, and afullWidthprop that makes the button span its container.HtmlButtonprovides the same theming for MJML ending tags and other raw-HTML contexts.-
theme.buttonsets the base button styling (color, background, border, border radius, font, and inner padding);theme.button.variantsoverrides those per named variant, optionally with per-breakpoint responsive values -
theme.button.backgroundImage(typically a gradient) overlaysbackgroundColor, which stays as the solid fallback for clients that don't render gradients (notably Outlook) -
HtmlButtonhas no alignment prop; horizontal placement is handled by the containing cell or layout -
Existing
MjmlButtonusages are unchanged when notheme.buttonis configuredExample theme
import { createTheme } from "@comet/mail-react"; const theme = createTheme({ button: { borderRadius: "6px", padding: "12px 28px", defaultVariant: "primary", variants: { primary: { backgroundColor: "#5B4FC7", color: "#FFFFFF" }, gradient: { backgroundColor: "#5B4FC7", backgroundImage: "linear-gradient(to right, #5B4FC7, #FF6B6B)", color: "#FFFFFF", }, }, }, }); declare module "@comet/mail-react" { interface ButtonVariants { primary: true; gradient: true; } }
Usage:
import { MjmlButton, MjmlMailRoot } from "@comet/mail-react"; <MjmlMailRoot theme={theme}> <MjmlSection> <MjmlColumn> <MjmlButton href="https://example.com">Default</MjmlButton> <MjmlButton href="https://example.com" variant="gradient" fullWidth> Gradient, full width </MjmlButton> </MjmlColumn> </MjmlSection> </MjmlMailRoot>;
-
Patch Changes
- b459ec7: Reduce published package size by keeping non-runtime build artifacts out of the bundle
@comet/site-react@9.0.0-beta.6
Minor Changes
-
4c1aeb2: Add
noFollowoption toExternalLinkBlockEditors can now mark an external link as
nofollowvia a new checkbox in the admin form. When enabled, the rendered<a>tag receivesrel="nofollow". Existing links are unaffected by an automatic block-data migration that setsnoFollowtofalse.
Patch Changes
-
d870d05: Fix Cookiebot consent initialization
Fix a race condition where the
CookiebotOnConsentReadyevent fires before theuseCookieBotCookieApihook is mounted.