Repository navigation
v4.8.0
Upgrading from 4.7 takes three steps. The API contract stays at 7, so barakoBrew 1.8.0 and barakoPress 0.12.0 keep working.
- Stop the API. One migration ships under
migrations/4.8.0/, from ExternalAuth: the store of used nonces for the id token grant. - Run
db-migrate, thendb-assert. A host without ExternalAuth can skip that file.scripts/upgrade-check.sh --listprints it and its rollback. - Start 4.8.0. The SMTP timeout per exchange is now 30 s (it was MailKit's 120 s); set
Modules:Email.Smtp:TimeoutSecondsif a relay needs longer.
Added
- A workflow email that never left is tried again inside the attempt.
EmailNotSentException
inBarakoCMS.Abstractionslets an email provider say a message cannot have been delivered. The
SMTP module throws it for a failure to connect or log in and for a 4xx or 5xx answer to MAIL FROM
or RCPT TO, and the Resend module for a connection not made and for a 429 or 503. The workflow
email action tries again on that exception only, up toWorkflows:Outbound:Retriesmore times,
cut so the tries fit in the lease.IEmailService.MaxNotSentDuration, with a default of null, is
how a provider says how long a not-sent try can take; a provider with none is sent once. Any other failure, a timeout included, is
still sent once and left to the durable queue. It is anInvalidOperationException, so code that
caught that from a provider still catches it (#1114). - Delivery describes an entry as schema.org JSON-LD. A content type can declare a
structuredDataType(Article,NewsArticle,BlogPosting,Event,ProductorWebPage)
on create or throughPUT /api/content-types/{name}/structured-data, and a read by slug then
carriesstructuredData, built from the fields holding thetitle,summary,date,image
andauthorroles.imageandauthorare new roles. A file this API serves at a relative path
is joined toApp:BaseUrlfor the image. The block is read off what delivery sends,
so a field that is not Public, a file that is not public and a filtered reference never reach it.
A type that declares nothing emits nothing.GET /api/meta/describelists the values under
structuredDataTypes, and the type description reports the type's own. See
docs/structured-data.md(#567). - Background work and database commands now show up in traces. With
Tracing:Otlp:Endpoint
set, the job queue exports a span for each claim, each run and the write that records its
outcome, tagged with the tenant and never the command. Each tick of scheduled publishing and of
collection syncs is a span, with one per tenant or per sync under it. Each outbound call through
the retry and the breaker is a span with one child per try and aretryevent from Carom's
retry hook for each retry. Npgsql's span of each database command made under one of these
spans or a request is exported cut down to the statement and the server it went to: no
parameter values, no connection string, no database user. A failed command, whose event quotes
the server's message, is not exported, and neither is a command with no parent, which includes
the background polls and a job handler's own commands. Each dropped span is counted on
barako.tracing.spans_dropped, by reason. Seedocs/tracing.md(#691). - Sign in with Apple. An OpenID Connect provider can now be set to
ResponseModeform_post,
which addsPOST /api/auth/oidc/{name}/callbackbeside the GET with the same state, nonce and
PKCE checks, and leaves its flow cookies SameSite=None so the provider's cross-site POST carries
them.SignedClientSecret(KeyId,TeamId, a P-256PrivateKeyin PEM) makes the client
secret an ES256 JWT, made for 30 days and made again when a day is left.EmailVerifiedMayBeText
takes Apple's text form ofemail_verified. ExternalAuth 4.5.0 (#786). - An id token grant for native apps.
POST /api/auth/oidc/{name}/id-tokentakes an id token a
MAUI or mobile app got from the provider's SDK, checks it as the callback does (issuer, signature,
expiry,email_verified) against the provider'sIdTokenAudienceslist, and answers with the
same tokens or MFA challenge. A token addressed to the web client is taken only when itsazp
names a listed app, so a token from the browser sign-in cannot be exchanged. The request must
carry the token's nonce. Each nonce is spent in the same commit as the sign-in, so a failed
sign-in can be retried with the same token, and works once until the token expires. It shares the
OIDC rate limit. An upgraded database needsmigrations/4.8.0/external-auth-used-nonces.sql,
which creates the emptymt_doc_oidc_used_noncestable and itsExpiresAtindex;
migrations/4.8.0/rollback-external-auth-used-nonces.sqldrops it. ExternalAuth 4.5.0 (#786). - A workflow template could not reach a referenced entry or list related ones.
{{data.Supplier.Email}}now reads a field of the entry areferencefield points at, and
{{#each data.Runners}}...{{/each}}renders its text once per entry a reference field points at.
What renders is what the user who fired the workflow may read, checked with the same permission
and sensitivity services asGET /api/contents/{id}: an entry they may not read renders empty,
like a missing one, and so does a Sensitive or Hidden field they may not see. References are
followed one level deep with a fixed number of reads per action. A loop renders the entries among
the first 50 ids and stops, and the attempt'serroron a succeeded attempt (or the action's
errorMessagein the execution log) says how many the field held. A dry run does not follow
references. Saving a workflow warns about a loop inside a loop, and about a parameter longer than
262,144 characters, which the engine sends as written with a note on the run (#828, #805). - Email templates as content. The new
emailblueprint createsemail-template(subject,
markdown body, layout, locale) andemail-layout(header, footer, logo, colours), neither publicly
deliverable. An Email workflow action can name one withTemplate(id or slug) instead of writing
SubjectandBody; a workflow without it sends exactly as before, and one with both is refused
with 400. Only a published template of the workflow's own tenant is sent: a missing, erased,
draft, archived or scheduled template, a missing or unpublished layout, or a text (or the body as
HTML in its layout) past 262,144 characters fails the action permanently, saying which. The body
is markdown with raw HTML off, placeholders resolve with the same engine as an inline body, values
are HTML encoded with their braces too, and links keep onlyhttp,httpsandmailto
addresses. With no layout, the tenant'ssiteentry gives the name, logo and colours. Saving a
workflow warns about the template's placeholders as it does for inline text.
POST /api/email-templates/{id}/previewrenders a template against an entry without sending, for
a caller withmanage_workflowswho can read both, showing the entry and the layout as that
caller reads them, under its ownemail-previewrate limit of 30 a minute per user. Markdown is
rendered with Markdig 1.4.0 (#829). - An email from a workflow could not link to the entry it was about.
{{links.console}}(and
{{links.edit}}) give the entry's page in the console from the newApp:ConsoleUrlsetting,
{{links.transition "Approve"}}the same page with the transition named,{{links.entry}}the
entry in this API fromApp:BaseUrl, and{{links.site "/approvals/"}}a page on the tenant's
site from theUrlof its site settings. Links are built from configuration only, carry no
token, and render empty when their base is not set. Signed one-click approvals are not part of
this (#840). - A renderer could not tell how long a delivery read may be kept, and nothing answered 304.
Every delivery read now sendsX-Barako-Cache-Class(short,longorno-store) beside the
Cache-Controlit always sent, which is unchanged. Eachshortorlongread carries a weak
ETag over the tenant and the body,Last-Modifiedwhere one timestamp covers the body (a type
description, a public file), and answersIf-None-MatchandIf-Modified-Sincewith a 304
and no body.Surrogate-KeyandCache-Tagname the tenant, the type, every type it refers to
or includes, and every entry or file the response was built from, all undert:<tenant>, at
most 32 tags and 1024 bytes per header, withX-Barako-Cache-Tags-Droppedcounting any left
out. A preview read staysno-storewith no tag or ETag, and so does a 404 for a public file
whose bytes are missing. Covers the public routes, the feed, the sitemap, the type description,
redirect lookup, public files and their metadata (BarakoCMS.Files 4.6.0) and semantic search
(BarakoCMS.AI 4.4.0). See "Cache classes, validators and tags" indocs/delivery-api.md(#973,
#561).
Changed
- One S3 call now fits inside the job lease. The S3 files module sets the SDK's retries and
timeout fromModules:Files.S3:MaxErrorRetry(2 when unset, the SDK's own was 4) and
TimeoutSeconds(45 when unset). The longest one call can take, 195 seconds with the defaults,
must fit in 80% of the shorter of the workflow runner's 5 minute lease andJobs:LeaseSeconds.
An unset value gives way to fit a shorter lease, so a host that started before still starts;
values set by hand that cannot fit stop the host with a message that names them. Each try now has
a time limit, so a large upload over a slow link may need a higherTimeoutSecondsand fewer
retries.MaxErrorRetryis always set on the client now, soAWS_MAX_ATTEMPTSno longer changes
it, andAWS_RETRY_MODE=adaptivecan wait for the SDK's rate limiter outside this bound (#1114). - SMTP sends have a timeout of their own.
Modules:Email.Smtp:TimeoutSeconds(default 30) is
MailKit's limit on each exchange with the relay, which was 120 s, and one limit over the connect
and login together. A relay that accepts the connection and never answers now fails as not sent
within it (#1114). - BarakoCMS.Forms 4.5.1 and BarakoCMS.Import 4.4.3 are rebuilt against BarakoCMS.Abstractions
4.8.0. Their source is the same as in 4.7.0.
Fixed
- An SMTP email could be sent twice when closing the connection failed. A failure after the
relay accepted the message is now logged and the send counts as sent, so the durable queue no
longer sends a second copy (#1114). - A module could not replace the OTP, email verification or email settings services, and nothing
said so. Core registered its own after the modules', so a module's implementation was never
called. Those three are now registered withTryAddand a module's registration wins.
IContentWriter,ISensitivityService,IContentSourcingPolicyandITemplateVariableExtractor
stay core's own, and a module that registers one now gets a startup warning naming the module and
the interface (#697). - An int field takes any 64-bit integer on every input path. A request body already did. Numeric
text and a raw JSON number stopped at Int32, so the same value was accepted on one path and
refused on another. A page's order in the Pages module now reads past Int32 (BarakoCMS.Pages
4.3.2). A fraction or a number past Int64 is still refused with a 400 naming the field, and stored
values read as before. Collection syncs are unchanged: a field declaredintgets a whole number,
and one declaredintegerornumberkeeps the cell text as it always has. See
docs/int-fields.md(#706).