Make the themed banner the default "." export and move the headless
components to "./headless". Remove unused VERSION export.
Signed-off-by: Émile Ré <emile@getprobo.com>
The server-side consent record is for audit purposes and does not need
to complete before the UI responds. Local state (cookie, script
activation) is applied synchronously, and the API call runs in the
background with queue fallback on failure.
Signed-off-by: Émile Ré <emile@getprobo.com>
Only copy dimensional style properties (width, height, margin, etc.)
to placeholders instead of blindly copying all cssText, which could
override layout properties like display: flex.
Handle multi-part TLDs (e.g. .co.uk, .com.au) when computing the root
domain for cookie deletion.
Signed-off-by: Émile Ré <emile@getprobo.com>
Improve accessibility across the cookie banner components: add
aria-modal/aria-labelledby/aria-describedby on dialog cards, aria-label
on icon-only buttons and category toggles, aria-expanded on cookie
detail disclosure, aria-hidden on decorative SVGs, and auto-focus into
dialogs when they become visible.
Signed-off-by: Émile Ré <emile@getprobo.com>
When visual elements (iframe, img, video, etc.) are blocked due to
missing cookie consent, display a styled placeholder that explains
which cookie category must be accepted and offers a link to open
the preference panel.
Signed-off-by: Émile Ré <emile@getprobo.com>
When a user changes their consent preferences, elements for rejected
categories are now deactivated: data attributes are restored, resources
are unloaded, and associated cookies are removed.
Signed-off-by: Émile Ré <emile@getprobo.com>
Allow customers to replace the built-in floating settings button with
their own re-open trigger (e.g. a footer link) by either placing a
<probo-settings-link> element anywhere on the page or manually setting
reopen-widget="custom" on the root. The settings-link auto-hides the
floating button on connect via a reopen-widget attribute change event.
Signed-off-by: Émile Ré <emile@getprobo.com>
Remove undocumented --probo-settings-bottom variable and use the
shared --probo-z-index variable instead of --probo-settings-z-index.
Signed-off-by: Émile Ré <emile@getprobo.com>
When a visitor with existing consent opened the preference panel via
the floating settings button and closed it, the state was always set
to "banner" instead of "hidden". Now check hasConsent so closing the
panel returns to the floating button when preferences are already saved.
Signed-off-by: Émile Ré <emile@getprobo.com>
Remove assets from the snapshot system and replace with a publish-based
document workflow that generates versioned ProseMirror documents.
- Remove snapshot_id/source_id from asset and asset_vendor models
- Delete AssetFilter (no longer needed without snapshot filtering)
- Add PublishAssetList service, GraphQL mutation, MCP tool, CLI command,
and n8n operation
- Add asset_list_document_id column to generated_documents table
- Generate ProseMirror documents with asset inventory tables
(name, type, amount, data types stored, owner, vendors)
- Add AssetListDocument resolver on Organization type
- Update frontend to remove snapshot routes/params and add publish dialog
- Add e2e tests for asset publish (immediate, with approvers, reuse, RBAC)
- Add migration script for converting legacy asset snapshots to documents
- Exclude ASSETS from snapshot type lists and e2e snapshot tests
- Move generated_documents SQL to coredata methods on Datum and Asset
- Clear generated document and SOA references on soft delete and archive
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
Drop the boolean implemented/not-implemented state in favor of a
mandatory CMMI maturity level enum (NONE, INITIAL, MANAGED, DEFINED,
QUANTITATIVELY_MANAGED, OPTIMIZING) stored as a Postgres enum type.
The migration backfills existing rows (NOT_IMPLEMENTED → NONE,
IMPLEMENTED → INITIAL), makes the column NOT NULL, and drops the old
implemented column and its enum type.
- maturityLevel is required on CreateControlInput and non-nullable (!)
in the GraphQL schema
- CLI displays human-readable CMMI labels instead of raw enum tokens
- SOA table and published document use a single Maturity column in
place of the old Implemented + Maturity columns
- Remove ControlImplementationState type and all implemented references
across backend, frontend, CLI, MCP, n8n, and E2E tests
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
Adds an optional CMMI 0-5 maturity level field to Control to support
ISO 27001 clause 9.1 effectiveness measurement and HITRUST CSF maturity
requirements. The field is nullable, framework-agnostic, and exposed
across all four API surfaces (GraphQL, MCP, CLI, n8n) plus the
generated SoA document.
Signed-off-by: Alejandro Juan <alejandrojuan@alejandrojuan.com>
Replace the `required` boolean column on cookie_categories with a `kind`
enum (NORMAL, NECESSARY, UNCATEGORISED). The Necessary category remains
undeletable and always-on for consent; the new Uncategorised category is
also undeletable but users can opt out of it.
When a category is deleted, its cookies are merged into the Uncategorised
category (lazy-created for legacy banners that don't have one yet).
Signed-off-by: Émile Ré <emile@getprobo.com>
Drop meetings and meeting_attendees tables, remove all meeting-related
code across GraphQL, MCP, CLI, N8N, webhooks, frontend, and e2e tests.
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
Mirror the SOA-to-document migration for the data list. Remove data
from the snapshot system and add a publish workflow that generates a
ProseMirror document for the full organization data inventory.
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
Expose document version approval quorums and decisions
through MCP, CLI, and n8n. This lets users inspect who
approved or rejected a document version, including the
rejection comment, without relying solely on the audit
log.
MCP tools: listDocumentVersionApprovalQuorums,
getDocumentVersionApprovalQuorum,
listDocumentVersionApprovalDecisions,
getDocumentVersionApprovalDecision.
CLI commands: document list-approval-quorums,
view-approval-quorum, list-approval-decisions,
view-approval-decision.
n8n operations: Get/Get Many Approval Quorums and
Approval Decisions on the Document resource.
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
Expose --probo-font-size and --probo-btn-radius so customers
can scale typography and button shape without overriding
internals. The type scale now uses calc() offsets from the
base variable. The settings button defaults now follow
--probo-accent so a single accent change updates both the
banner and the floating button.
Signed-off-by: Émile Ré <emile@getprobo.com>
Headless components are behavioral wrappers meant to be styled
by the consumer with regular CSS. Shadow DOM on each child
created unnecessary style boundaries with no visual content to
protect. Only ProboSettingsButton retains its own shadow root
since it renders encapsulated styled markup.
Also removes the auto-registerComponents() side effect from
the main entrypoint so consumers opt in explicitly.
Signed-off-by: Émile Ré <emile@getprobo.com>
Store baseUrl as URL and build endpoints with new URL(path, base).
Accept URL | string in fetchJSON to avoid unnecessary .href calls.
Signed-off-by: Émile Ré <emile@getprobo.com>
Validate that <probo-preference-panel> contains <probo-category-list>
and <probo-save-button>, and that the category template includes
<probo-category-toggle> and <probo-cookie-list>.
Signed-off-by: Émile Ré <emile@getprobo.com>
Introduce Shadow DOM-based custom elements that let customers build
their own cookie banner and preference panel while the SDK validates
structural compliance and auto-renders categories/cookies from config.
Components: probo-cookie-banner (root), probo-banner, probo-accept-button,
probo-reject-button, probo-customize-button, probo-preference-panel,
probo-category-list, probo-category, probo-category-toggle,
probo-cookie-list, probo-cookie, probo-save-button, probo-settings-button.
Signed-off-by: Émile Ré <emile@getprobo.com>
Expose webhook subscription CRUD and event listing through the MCP API
(list, get, create, update, delete subscriptions + list events) and add
a new webhook resource to the N8N node with matching operations.
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
The absolute-positioned collapse button overlapped the nav items
whenever the sidebar content exceeded the viewport. With the page now
scrolling at the document level, the overlap became permanent.
Restructure the aside as a flex column: nav list in a flex-1 region,
collapse button in a sticky bottom-0 container with a border-t
separator. The button pins to the viewport bottom while scrolling and
never overlaps the items above.
Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
The previous layout nested two scroll regions, sidebar and main, each
with its own scrollbar. Combined with the fixed 100vh flex container,
any child overflow (notably the sidebar nav) spilled past bg-level-0
and exposed the browser's default white background -- most visible in
dark mode as a white strip at the bottom of the viewport.
Switch to a single page-level scroll: pin the header with fixed, let
the wrapper grow with min-h-screen, and drop main's internal overflow.
The drawer becomes fixed too so it stays pinned while the page scrolls
and gets an opaque background to cover scrolled content behind it.
Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
The flush function pruned expired entries in memory but re-read from
localStorage before writing back, so the age filter was never persisted.
Apply the age cutoff to the final write filter and remove the early
return that skipped the write entirely on full send failure.
Signed-off-by: Émile Ré <emile@getprobo.com>
Re-read localStorage after network calls in flush() to avoid
discarding entries added by concurrent enqueue() calls. Also
call flush() in the cookie fast-path of load() so queued
consent retries are always drained.
Signed-off-by: Émile Ré <emile@getprobo.com>
- Rename MAX_RETRIES to MAX_ATTEMPTS (3 total) to fix
misleading naming
- Skip retry loop on caller-initiated aborts so explicit
cancellations terminate immediately
- Preserve original script type via data-type attribute
instead of always forcing text/javascript
- Recreate MutationObserver when consent changes so newly
added elements use fresh consent data
- Fix package.json exports: point main at ESM bundle and
add proper exports map with IIFE as separate entry
Signed-off-by: Émile Ré <emile@getprobo.com>
Reduce timeout/retry defaults (5s timeout, 2 retries, 500ms base delay)
to cap worst-case page-load blocking at ~12s instead of ~36s.
Add a localStorage-backed queue that persists failed consent POSTs and
replays them on next page load, closing the compliance gap where a
network failure could permanently lose the server-side audit record.
Signed-off-by: Émile Ré <emile@getprobo.com>
Unblock scripts, iframes, images, and other resource-loading
elements marked with data-cookie-consent when their category
is consented. Uses MutationObserver for dynamically added
elements. Restricted to known resource tags with data-href
support for link elements.
Signed-off-by: Émile Ré <emile@getprobo.com>
CookieBannerClient wraps the cookie banner REST API with
methods to load config, accept/reject/customize consent,
and manage visitor identity. Consent state is persisted in
a probo_consent cookie to skip API calls on return visits,
with version-aware invalidation and configurable expiry.
Signed-off-by: Émile Ré <emile@getprobo.com>
Introduces fetchJSON<T> with timeout, exponential backoff
with jitter on network errors and 5xx/429, and error classes
that match the cookie banner API error shape.
Signed-off-by: Émile Ré <emile@getprobo.com>
Introduce the boilerplate for a new public npm package that will
serve as the cookie consent banner JavaScript SDK. The package
uses esbuild to produce both an IIFE bundle (for script tag
embedding) and an ESM module. Versioning is independent from the
monorepo: CI compares package.json against npm and only publishes
when the version changes.
Signed-off-by: Émile Ré <emile@getprobo.com>