Version Packages#5
Open
github-actions[bot] wants to merge 1 commit into
Open
Conversation
github-actions
Bot
force-pushed
the
changeset-release/main
branch
2 times, most recently
from
June 23, 2026 22:26
3ce5a29 to
b6b183b
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
6 times, most recently
from
July 5, 2026 21:50
e8d0fae to
0a09a0c
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
July 6, 2026 01:38
0a09a0c to
1e936a4
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.
Releases
@ogs-tech/press-cms@1.0.0
Major Changes
936ece7Thanks @odenirdev! - feat!: Atomic Design component palette — unified{owner}-{layer}.{name}schemeBREAKING (wire + API): the ad-hoc
press.*/section.*/chrome.*prefixesare replaced by ONE Atomic Design scheme where the Strapi category encodes
{owner}-{layer}(owner ∈ preset|custom, layer ∈ atom|molecule|organism|config|layout|template) and stored
__componentvalues change accordingly:press.{paragraph,heading,list,quote,image,button,separator,spacer}→preset-atom.*;press.nav-item→preset-molecule.nav-item;press.{seo,theme-colors,theme-radius,cookie-consent,cookie-category}→preset-config.*.section.{hero,cta}andchrome.{navbar,footer}unify underpreset-organism.*(one layer; placement — body vs header/footer — is declaredper content-type
schema.json, not by the category).hero/ctaare nowbody-only.
custom/custom-section/custom-chrome) to atomic-LAYER folders (custom-<layer>/, e.g.custom-organism/);admitCustomBlocksnow admits everycustom-*block intoALL engine Dynamic Zones (universal placement — the editor decides where),
dropping the per-category placement map. Legacy bare
custom.*is stilladmitted for a forgiving migration.
press-web: exported registries renamed (
referenceBlocks→atomBlocks;sectionBlocks+chromeBlocks→organismBlocks) and the base block typesrenamed (
PressParagraph→PresetAtomParagraph,SectionHero→PresetOrganismHero,ChromeNavbar→PresetOrganismNavbar, …). The generator,PressSchemacontract,urn/blockKeyprimitives, and theplugin::press-cms.*plugin id are unchanged (the product name "press" is not a component category).
The scaffolder ships the migrated
custom-organism.calloutexample.#8
a6bdc84Thanks @odenirdev! - feat!: block-composable site chrome (chrome.*)The site header and footer become block-composed: the
site-settingsingle typegains two Dynamic Zones (
header,footer) admitting a new engine-ownedchrome.*category (chrome.navbar,chrome.footer) pluspress.*,section.*, and adoptercustom.*blocks. The serializer walks all three engineDZs and follows nested component references; the generator types nested
components (without
__component), skips relations, and emitsHeaderBlocks/FooterBlocksunions.mapSiteSettingshydrates the zones (brandinjection + nav resolution);
BlockRenderermerges a newchromeBlocksregistry(adopter-overridable); the host layout renders both zones through the block
pipeline.
bootstrap()seeds a default composition (navbar + footer) exactlyonce.
press-shared:Attrgains typedcomponent/repeatablekeys (additive).BREAKING (press-cms):
site-setting.headerNavis removed. Strapi drops its dataon schema sync — there is no automated migration. After upgrading, re-enter the
nav links once inside the seeded Navbar block (Site Settings → Header).
BREAKING (press-web):
SiteNavis no longer exported (the navbar renders linksinternally) and
ResolvedPressConfig.navis replaced byResolvedPressConfig.chrome({ header, footer }hydrated block arrays).Override the chrome like any block:
components={{ 'chrome.navbar': MyNavbar }}.Minor Changes
#9
21c793bThanks @odenirdev! - feat(cms): component-picker UX — per-block icons + human category labelsEvery engine component JSON now sets
info.icon(Strapi's fixed icon enum), sothe admin "Pick one component" dialog stops rendering the generic grid fallback
for all blocks:
press.paragraph→write,press.image→picture,section.hero→landscape,chrome.navbar→layout, and so on.The plugin also ships its first admin bundle (
./strapi-adminexport, built bythe same
strapi-plugin build). Its single job isregisterTrads: the pickerresolves each category accordion title through react-intl using the RAW
category string as the message id, so the bundle registers unprefixed keys —
press→ "Blocks",section→ "Sections",chrome→ "Site chrome",custom→ "Custom blocks" (en + pt/pt-BR) — labelling the picker withouttouching component uids (a uid is wire/DB contract; labels are presentation).
Adopters keep the final word:
src/admin/app.tsxconfig.translationstakesprecedence over these engine defaults.
#9
21c793bThanks @odenirdev! - feat!: cookie-consent — the first engine plugin, introducing the'plugin'canonicalEngine plugins (press-web).
Entitygains'plugin'(additive) and thenew
PressPlugin<Id>contract (extends Canonical<'plugin'>,id,enabled)formalizes the plugin family: an optional engine capability configured through
Site Settings, resolved by a pure mapper into the new
ResolvedPressConfig.pluginsnamed map, and mounted explicitly by the hostlayout — no runtime registry. Plugin identity is synthetic
(
urn:plugin:cookie-consent), never CMS-sourced.Cookie consent (press-web). New
CookieConsentBanner(the engine's firststateful client component), the
useConsent()hook, and the consent store:hasConsent('analytics')(fail-closed),acceptAll/rejectAll/setConsent/resetConsent,parseConsentCookie(server-side seam), andbuildConsentBootstrapScript()— a pre-paint inline script the host layoutinjects so a decided visitor never sees the banner flash. The decision lives
in a versioned first-party cookie (
press_consent, SameSite=Lax, 180d), neverread via
cookies()in the RSC tree (static/ISR stays intact). The resolvedplugin FAILS OPEN: an unreachable CMS still yields an enabled banner with the
engine's default copy — a consent gate must not vanish on a CMS hiccup.
Consent categories are a closed code union (
necessary | analytics | marketing); editors toggle and re-word them, never rename keys.Cookie consent (press-cms). New
press.cookie-consent+press.cookie-categoryconfig components (injected, never DZ-admitted), acookieConsentattribute on Site Settings with deep populate (nestedcategories + privacy page slug), and a run-once seed (
cookieConsentSeededplugin-store flag) that writes only the
enabledbooleans — default copylives web-side; an editor-disabled banner is respected forever.
BREAKING (press-web):
ResolvedPressConfiggains a REQUIREDpluginsfield.Runtime is additive — every object produced by
getSiteConfigcarries it —but adopter code that hand-constructs a literal (test fixtures, mocks) fails
tscuntil it addsplugins: { cookieConsent: ... }(or builds the valuethrough
mapSiteSettings). The host template'slayout.tsxalso changed(bootstrap script + banner mount) and is re-materialized on the next
press dev/build.#9
21c793bThanks @odenirdev! - feat(cms): custom block kinds — placement-scoped adopter categoriesThe adopter extension point now carries placement semantics per category
folder (
admitCustomBlocks):src/components/custom/→ every engine Dynamic Zone (pagebody+site-setting
header/footer) — the existing contract, unchanged;src/components/custom-section/→ the pagebodyonly;src/components/custom-chrome/→ the site-settingheader/footeronly,never the page body.
Purely additive: existing
custom.*blocks keep their behavior and uids. Theengine still never names individual adopter blocks — only the
custom*categories are the stable contract. Note:
custom-chrome.*blocks do notreceive the brand/links hydration that
chrome.navbargets frommapSiteSettings; they render from their stored attributes alone.b11ced9Thanks @odenirdev! - feat: editable header navigationCMS gains the
press.nav-itemcomponent (injected, Site-Settings-only) and arepeatable
headerNavfield on the Site Settings single type. The Site Settingscontroller deep-populates
headerNav.page(slug only), and Web resolves each iteminto a final link (page wins over url; the home slug collapses to
/; items withneither are dropped) and ships a
SiteNavclient component rendered in the hostheader with active-link highlighting. Additive only — no
PressSchema/generator/generated.ts/adopter-zone change. Empty/unreachable/malformed
CMS → header renders the logo only.
Side effect: replacing the Site Settings
populate=*with an explicit deeppopulate (required to reach
headerNav.page) also deep-populatesseo.image,which the one-level
populate=*did not reach — so the SEO OG image(
defaultOgImage) now resolves from the CMS instead of always being undefined.#9
21c793bThanks @odenirdev! - feat(cms): seed a Privacy Policy page template once at bootstrapbootstrap()now seeds a "Privacy Policy" page (slugprivacy-policy) exactlyonce, following the chrome-seed semantics: a
privacyPageSeededplugin-storeflag makes the pass literal-once, an adopter page already occupying the slug
wins (seed marks itself done without writing), and an editor-deleted page is
respected forever. The page is created as a DRAFT — the engine never publishes
content on its own.
The template is structure + placeholder guidance composed from existing
press.*atoms (intro, Data We Collect, Cookies, How We Use Your Data, DataSharing, Your Rights, Contact) — no legal boilerplate is embedded; the editor
writes and owns the actual policy text.
#6
490bdc7Thanks @odenirdev! - feat: composite section blocks (section.*)Adds an engine-owned palette of composite sections under a new
section.*category:
section.heroandsection.cta. CMS injects both components and liststhem statically in the page
bodyDynamic Zone; they flow through the unchangedtype-sync pipeline (all fields are flat scalar/media/enum), so
serialize-schemaand the generator are untouched. Web ships
Hero/Ctarenderers behind a separatesectionBlocksregistry thatBlockRenderermerges betweenreferenceBlocksandthe adopter's
components— each section is born branded by the Site Settings theme(theme.css consumes
var(--press-*)tokens) and overridable viacomponents={{ 'section.hero': MyHero }}. Additive and non-breaking:press.*andcustom.*are unchanged; adopters gainsection.*onpress upgrade.Patch Changes
#8
a6bdc84Thanks @odenirdev! - fix(cms): silence the schema-poll http log line in developmentpress devpollsGET /api/press/schemaevery ~2s (the type-sync watcher),and Strapi's
strapi::loggermiddleware logs every request unconditionally —flooding the dev log with one line per poll. The plugin now wraps
strapi.log.httpduringregister()and drops messages for that oneengine-owned path, in development only: in production the watcher never runs,
and a stray hit on the schema endpoint stays visible.
@ogs-tech/press-web@1.0.0
Major Changes
936ece7Thanks @odenirdev! - feat!: Atomic Design component palette — unified{owner}-{layer}.{name}schemeBREAKING (wire + API): the ad-hoc
press.*/section.*/chrome.*prefixesare replaced by ONE Atomic Design scheme where the Strapi category encodes
{owner}-{layer}(owner ∈ preset|custom, layer ∈ atom|molecule|organism|config|layout|template) and stored
__componentvalues change accordingly:press.{paragraph,heading,list,quote,image,button,separator,spacer}→preset-atom.*;press.nav-item→preset-molecule.nav-item;press.{seo,theme-colors,theme-radius,cookie-consent,cookie-category}→preset-config.*.section.{hero,cta}andchrome.{navbar,footer}unify underpreset-organism.*(one layer; placement — body vs header/footer — is declaredper content-type
schema.json, not by the category).hero/ctaare nowbody-only.
custom/custom-section/custom-chrome) to atomic-LAYER folders (custom-<layer>/, e.g.custom-organism/);admitCustomBlocksnow admits everycustom-*block intoALL engine Dynamic Zones (universal placement — the editor decides where),
dropping the per-category placement map. Legacy bare
custom.*is stilladmitted for a forgiving migration.
press-web: exported registries renamed (
referenceBlocks→atomBlocks;sectionBlocks+chromeBlocks→organismBlocks) and the base block typesrenamed (
PressParagraph→PresetAtomParagraph,SectionHero→PresetOrganismHero,ChromeNavbar→PresetOrganismNavbar, …). The generator,PressSchemacontract,urn/blockKeyprimitives, and theplugin::press-cms.*plugin id are unchanged (the product name "press" is not a component category).
The scaffolder ships the migrated
custom-organism.calloutexample.#8
a6bdc84Thanks @odenirdev! - feat(web)!: canonical urn identity —urn:{entity}:{id}on Page and Site SettingsNew web-only identity primitives in
packages/web/src/urn.ts, exported from thepackage root: the closed
Entityunion ('page' | 'site-setting'), thetemplate-literal
Urn<E>(urn:{entity}:{id}), theCanonical<E>interface(
{ urn: Urn<E> }), and the purebuildUrn(entity, id)factory. The wirecontract, press-cms, and press-shared are untouched — a urn is never sent or
stored by the CMS.
Pagenow extendsCanonical<'page'>: the new puremapPagemapper (mirroringthe
mapSiteSettingspure-mapper + thin-fetcher split) attachesurn:page:{documentId}right after the fetch.ResolvedPressConfigextendsCanonical<'site-setting'>:mapSiteSettingsattaches the synthetic constanturn:site-setting:default(single type — one record, identity neverCMS-sourced, present even when the CMS is unreachable).
blockKeynow formatsits React key through the same primitive (
press.image:5→urn:press.image:5) — a computed identity, never stored on the block; blockKeywas never exported, so no public surface changes shape there.
BREAKING (press-web):
PageandResolvedPressConfiggain a REQUIREDurnfield. Runtime is additive — every object produced by
getPage/getSiteConfigcarries it automatically — but adopter code that hand-constructs a literal of
either type (e.g. a test fixture or a mock) fails
tscuntil it addsurn(
'urn:page:<documentId>'/'urn:site-setting:default').#8
a6bdc84Thanks @odenirdev! - feat!: block-composable site chrome (chrome.*)The site header and footer become block-composed: the
site-settingsingle typegains two Dynamic Zones (
header,footer) admitting a new engine-ownedchrome.*category (chrome.navbar,chrome.footer) pluspress.*,section.*, and adoptercustom.*blocks. The serializer walks all three engineDZs and follows nested component references; the generator types nested
components (without
__component), skips relations, and emitsHeaderBlocks/FooterBlocksunions.mapSiteSettingshydrates the zones (brandinjection + nav resolution);
BlockRenderermerges a newchromeBlocksregistry(adopter-overridable); the host layout renders both zones through the block
pipeline.
bootstrap()seeds a default composition (navbar + footer) exactlyonce.
press-shared:Attrgains typedcomponent/repeatablekeys (additive).BREAKING (press-cms):
site-setting.headerNavis removed. Strapi drops its dataon schema sync — there is no automated migration. After upgrading, re-enter the
nav links once inside the seeded Navbar block (Site Settings → Header).
BREAKING (press-web):
SiteNavis no longer exported (the navbar renders linksinternally) and
ResolvedPressConfig.navis replaced byResolvedPressConfig.chrome({ header, footer }hydrated block arrays).Override the chrome like any block:
components={{ 'chrome.navbar': MyNavbar }}.#9
21c793bThanks @odenirdev! - feat!: cookie-consent — the first engine plugin, introducing the'plugin'canonicalEngine plugins (press-web).
Entitygains'plugin'(additive) and thenew
PressPlugin<Id>contract (extends Canonical<'plugin'>,id,enabled)formalizes the plugin family: an optional engine capability configured through
Site Settings, resolved by a pure mapper into the new
ResolvedPressConfig.pluginsnamed map, and mounted explicitly by the hostlayout — no runtime registry. Plugin identity is synthetic
(
urn:plugin:cookie-consent), never CMS-sourced.Cookie consent (press-web). New
CookieConsentBanner(the engine's firststateful client component), the
useConsent()hook, and the consent store:hasConsent('analytics')(fail-closed),acceptAll/rejectAll/setConsent/resetConsent,parseConsentCookie(server-side seam), andbuildConsentBootstrapScript()— a pre-paint inline script the host layoutinjects so a decided visitor never sees the banner flash. The decision lives
in a versioned first-party cookie (
press_consent, SameSite=Lax, 180d), neverread via
cookies()in the RSC tree (static/ISR stays intact). The resolvedplugin FAILS OPEN: an unreachable CMS still yields an enabled banner with the
engine's default copy — a consent gate must not vanish on a CMS hiccup.
Consent categories are a closed code union (
necessary | analytics | marketing); editors toggle and re-word them, never rename keys.Cookie consent (press-cms). New
press.cookie-consent+press.cookie-categoryconfig components (injected, never DZ-admitted), acookieConsentattribute on Site Settings with deep populate (nestedcategories + privacy page slug), and a run-once seed (
cookieConsentSeededplugin-store flag) that writes only the
enabledbooleans — default copylives web-side; an editor-disabled banner is respected forever.
BREAKING (press-web):
ResolvedPressConfiggains a REQUIREDpluginsfield.Runtime is additive — every object produced by
getSiteConfigcarries it —but adopter code that hand-constructs a literal (test fixtures, mocks) fails
tscuntil it addsplugins: { cookieConsent: ... }(or builds the valuethrough
mapSiteSettings). The host template'slayout.tsxalso changed(bootstrap script + banner mount) and is re-materialized on the next
press dev/build.Minor Changes
#10
260d8eaThanks @odenirdev! - feat(web):componentcanonical —urn:component:{uid}type-level identityEntitygains a 4th member'component'(additive), plus acomponentUrn(uid)factory (exported from the package root) formatting
urn:component:{uid}for thepalette registries (
press.*/section.*/chrome.*/custom.*). This is aTYPE-level identity — distinct from the STORED identities (page/site-setting/
plugin) and from
blockKey's COMPUTED per-instance key. No object implementsCanonical<'component'>; the first consumer isBlockRenderer'sunknown-component dev warning, now citing the canonical
urn:component:…form.b11ced9Thanks @odenirdev! - feat: editable header navigationCMS gains the
press.nav-itemcomponent (injected, Site-Settings-only) and arepeatable
headerNavfield on the Site Settings single type. The Site Settingscontroller deep-populates
headerNav.page(slug only), and Web resolves each iteminto a final link (page wins over url; the home slug collapses to
/; items withneither are dropped) and ships a
SiteNavclient component rendered in the hostheader with active-link highlighting. Additive only — no
PressSchema/generator/generated.ts/adopter-zone change. Empty/unreachable/malformed
CMS → header renders the logo only.
Side effect: replacing the Site Settings
populate=*with an explicit deeppopulate (required to reach
headerNav.page) also deep-populatesseo.image,which the one-level
populate=*did not reach — so the SEO OG image(
defaultOgImage) now resolves from the CMS instead of always being undefined.#6
490bdc7Thanks @odenirdev! - feat: composite section blocks (section.*)Adds an engine-owned palette of composite sections under a new
section.*category:
section.heroandsection.cta. CMS injects both components and liststhem statically in the page
bodyDynamic Zone; they flow through the unchangedtype-sync pipeline (all fields are flat scalar/media/enum), so
serialize-schemaand the generator are untouched. Web ships
Hero/Ctarenderers behind a separatesectionBlocksregistry thatBlockRenderermerges betweenreferenceBlocksandthe adopter's
components— each section is born branded by the Site Settings theme(theme.css consumes
var(--press-*)tokens) and overridable viacomponents={{ 'section.hero': MyHero }}. Additive and non-breaking:press.*andcustom.*are unchanged; adopters gainsection.*onpress upgrade.@ogs-tech/create-press@0.1.1
Patch Changes
936ece7Thanks @odenirdev! - feat!: Atomic Design component palette — unified{owner}-{layer}.{name}schemeBREAKING (wire + API): the ad-hoc
press.*/section.*/chrome.*prefixesare replaced by ONE Atomic Design scheme where the Strapi category encodes
{owner}-{layer}(owner ∈ preset|custom, layer ∈ atom|molecule|organism|config|layout|template) and stored
__componentvalues change accordingly:press.{paragraph,heading,list,quote,image,button,separator,spacer}→preset-atom.*;press.nav-item→preset-molecule.nav-item;press.{seo,theme-colors,theme-radius,cookie-consent,cookie-category}→preset-config.*.section.{hero,cta}andchrome.{navbar,footer}unify underpreset-organism.*(one layer; placement — body vs header/footer — is declaredper content-type
schema.json, not by the category).hero/ctaare nowbody-only.
custom/custom-section/custom-chrome) to atomic-LAYER folders (custom-<layer>/, e.g.custom-organism/);admitCustomBlocksnow admits everycustom-*block intoALL engine Dynamic Zones (universal placement — the editor decides where),
dropping the per-category placement map. Legacy bare
custom.*is stilladmitted for a forgiving migration.
press-web: exported registries renamed (
referenceBlocks→atomBlocks;sectionBlocks+chromeBlocks→organismBlocks) and the base block typesrenamed (
PressParagraph→PresetAtomParagraph,SectionHero→PresetOrganismHero,ChromeNavbar→PresetOrganismNavbar, …). The generator,PressSchemacontract,urn/blockKeyprimitives, and theplugin::press-cms.*plugin id are unchanged (the product name "press" is not a component category).
The scaffolder ships the migrated
custom-organism.calloutexample.@ogs-tech/press-shared@0.2.0
Minor Changes
#8
a6bdc84Thanks @odenirdev! - feat!: block-composable site chrome (chrome.*)The site header and footer become block-composed: the
site-settingsingle typegains two Dynamic Zones (
header,footer) admitting a new engine-ownedchrome.*category (chrome.navbar,chrome.footer) pluspress.*,section.*, and adoptercustom.*blocks. The serializer walks all three engineDZs and follows nested component references; the generator types nested
components (without
__component), skips relations, and emitsHeaderBlocks/FooterBlocksunions.mapSiteSettingshydrates the zones (brandinjection + nav resolution);
BlockRenderermerges a newchromeBlocksregistry(adopter-overridable); the host layout renders both zones through the block
pipeline.
bootstrap()seeds a default composition (navbar + footer) exactlyonce.
press-shared:Attrgains typedcomponent/repeatablekeys (additive).BREAKING (press-cms):
site-setting.headerNavis removed. Strapi drops its dataon schema sync — there is no automated migration. After upgrading, re-enter the
nav links once inside the seeded Navbar block (Site Settings → Header).
BREAKING (press-web):
SiteNavis no longer exported (the navbar renders linksinternally) and
ResolvedPressConfig.navis replaced byResolvedPressConfig.chrome({ header, footer }hydrated block arrays).Override the chrome like any block:
components={{ 'chrome.navbar': MyNavbar }}.playground@0.1.1
Patch Changes
936ece7,a6bdc84,a6bdc84,260d8ea,21c793b,b11ced9,490bdc7]:playground-cms@0.1.1
Patch Changes
936ece7,a6bdc84,21c793b,21c793b,21c793b,b11ced9,21c793b,a6bdc84,490bdc7]: