Skip to content

9.0.0-beta.6

Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 02 Jul 12:47
ea27402

@comet/admin@9.0.0-beta.6

Minor Changes

  • 15e771b: Add TimeRangePicker and TimeRangePickerField components

    These MUI X-based components complete the set of date/time components in @comet/admin and replace the deprecated TimeRangePicker, TimeRangeField and FinalFormTimeRangePicker from @comet/admin-date-time.

    The value and the value passed to onChange are a TimeRange object with start and end as 24-hour time strings (HH:mm):

    type TimeRange = {
        start: string | null;
        end: string | null;
    };

Patch Changes

  • b4ba869: Fix Data Grid Excel export for singleSelect columns

    When a singleSelect column uses valueOptions, Excel export now resolves the exported cell value to the matching option label unless a custom valueFormatter overrides it.

  • 57678d0: Fix FinalFormNumberInput dirtying the form on mount when the initial value is null

    The value-sync effect inside FinalFormNumberInput ran on mount and called input.onChange(undefined) whenever input.value was empty. For a form whose initial value was null, this silently normalized the value to undefined, making the field dirty before any user interaction and breaking dirty-tracking features such as EditDialog, SaveBoundary, and the unsaved-changes router prompt.

    The mount-time sync now only updates the formatted display string. The empty-input normalization to undefined still happens on real user interaction in handleBlur.

  • 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, TimeRangeField and FinalFormTimeRangePicker and add a "Legacy" prefix to their class-names and theme component-key

    Their new counterparts in @comet/admin are now considered stable.

    Consider using the new components from @comet/admin

    In 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 defaultProps or styleOverrides in the theme:

    • CometAdminTimeRangePicker -> CometAdminLegacyTimeRangePicker

Minor Changes

  • 1a83c01: Deprecate the @comet/admin-date-time package

    All of its components now have stable replacements in @comet/admin. The remaining exports (DatePickerNavigation, DateFnsLocaleProvider, DateFnsLocaleContext and useDateFnsLocale) 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 BrevoContactForm sending sendDoubleOptIn in update mutation

    sendDoubleOptIn is not a valid field of BrevoContactUpdateInput and 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 noFollow option to ExternalLinkBlock

    Editors can now mark an external link as nofollow via a new checkbox in the admin form. When enabled, the rendered <a> tag receives rel="nofollow". Existing links are unaffected by an automatic block-data migration that sets noFollow to false.

  • 7fbe2a7: Add allowPageDelete option to disable deletion of pages in the PageTree. When set to false, the delete option is hidden in the Admin UI and the API blocks deletion attempts.

  • 7ab96c2: Add SearchHeaderItem component for full-text search

    The SearchHeaderItem component renders a search input (intended for the header) that opens a dropdown with the results of the myFullTextSearch query. The search is restricted to the currently selected content scope. Clicking a result opens the corresponding entity using the entityDependencyMap from the DependenciesConfig (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 AnonymousBlockInterface type

  • 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 StartBuildsDialog data grid

    The buildTemplates query 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 @RequiredPermission from entity in resolver permissions

    The UserPermissionsGuard now falls back to the entity's @RequiredPermission decorator 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 @RequiredPermission on generated resolvers if the entity already has @RequiredPermission set. This avoids redundant permission declarations.

@comet/brevo-api@9.0.0-beta.6

Major Changes

  • f932845: Update @getbrevo/brevo to v5

    The transactional mail service's send method now accepts a SendTransacEmailRequest (without sender) instead of a SendSmtpEmail. 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 AffectedScope to return multiple scopes

    The argsToScope function can now return ContentScope[] in addition to a single ContentScope. 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 (and findUserForLogin / findUserForLoginOrThrow) to UserPermissionsUserServiceInterface

    The throwing getUser and getUserForLogin methods on UserPermissionsUserServiceInterface are 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 define getUser / getUserForLogin continue 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 noFollow option to ExternalLinkBlock

    Editors can now mark an external link as nofollow via a new checkbox in the admin form. When enabled, the rendered <a> tag receives rel="nofollow". Existing links are unaffected by an automatic block-data migration that sets noFollow to false.

  • 67938b2: Filter myFullTextSearch results by the entity's required permission

    The requiredPermission of an entity (declared via the @RequiredPermission decorator) is now included in both the EntityInfo and EntityInfoFullText SQL views.

    The myFullTextSearch query (formerly fullTextSearch) 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. The my prefix 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 allowPageDelete option to disable deletion of pages in the PageTree. When set to false, the delete option is hidden in the Admin UI and the API blocks deletion attempts.

  • 1b37655: Add scope support to myFullTextSearch

    The EntityInfoFullText view now includes a scopes column, and the myFullTextSearch query accepts an optional scope argument to restrict results to a single content scope.

    The scopes are derived from either a scope property on the entity (simple case) or the @ScopedEntity decorator. To support building the scopes in SQL, @ScopedEntity accepts 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 @ScopedEntity is 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 a scope property) — otherwise creating the EntityInfoFullText view throws.

  • 70a77db: Reuse @RequiredPermission from entity in resolver permissions

    The UserPermissionsGuard now falls back to the entity's @RequiredPermission decorator 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 @RequiredPermission on generated resolvers if the entity already has @RequiredPermission set. This avoids redundant permission declarations.

  • 8498a7c: Export EntityInfoObject, EntityInfoFullTextObject and PaginatedEntityInfo

    This 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 entityInfo relation to return name and secondary information.

Patch Changes

  • 35e9e0d: Fix copying the home page creating a second page with the slug home

    Previously, 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 slug home is forbidden). The copy now receives a different slug if the target scope already has a home page, and keeps home only when there is none yet.

  • 91f4a9f: Fix DAM file listing failing for files larger than ~2 GB

    The size field of DamFile and FileUpload was exposed as a GraphQL Int, 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 with Int 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 as BigInt, which represents the full range of file sizes stored in the database (bigint).

  • affbb11: Load jsdom lazily for SVG validation

    jsdom (~90 MB resident) was imported and instantiated at module load time, so importing anything from @comet/cms-api pulled 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-node lazily in KubernetesService

    @kubernetes/client-node (~85 MB resident) was statically imported, so importing anything from @comet/cms-api pulled 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 when KubernetesService actually connects to a cluster, reducing the package's base memory footprint.

  • 6793853: Load openai lazily in AzureOpenAiContentGenerationService

    The openai client was statically imported, so importing anything from @comet/cms-api pulled 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 by jsdom) instead of the custom XML-based check

    The previous implementation parsed SVGs with fast-xml-parser and applied a hand-written allow/deny list to reject scripts, event handlers and unsafe links.
    SVGs are now sanitized with the vetted DOMPurify library and rejected when it has to strip any tags or attributes, providing more robust protection against XSS vectors in uploaded SVGs.

    The role attribute 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 MjmlButton and add a new HtmlButton component

    MjmlButton now supports theme-based styling through theme.button, an optional variant prop, and a fullWidth prop that makes the button span its container. HtmlButton provides the same theming for MJML ending tags and other raw-HTML contexts.

    • theme.button sets the base button styling (color, background, border, border radius, font, and inner padding); theme.button.variants overrides those per named variant, optionally with per-breakpoint responsive values

    • theme.button.backgroundImage (typically a gradient) overlays backgroundColor, which stays as the solid fallback for clients that don't render gradients (notably Outlook)

    • HtmlButton has no alignment prop; horizontal placement is handled by the containing cell or layout

    • Existing MjmlButton usages are unchanged when no theme.button is configured

      Example 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 noFollow option to ExternalLinkBlock

    Editors can now mark an external link as nofollow via a new checkbox in the admin form. When enabled, the rendered <a> tag receives rel="nofollow". Existing links are unaffected by an automatic block-data migration that sets noFollow to false.

Patch Changes

  • d870d05: Fix Cookiebot consent initialization

    Fix a race condition where the CookiebotOnConsentReady event fires before the useCookieBotCookieApi hook is mounted.