Run cookie detection regardless of banner state

Decouple detection from the banner's active state so admins
can discover cookies before making the banner visible. The
client now starts the detector even when the config endpoint
returns 404, and the detector stops itself if the report
endpoint returns 404 (wrong or deleted banner ID).

Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
Émile Ré
2026-05-02 19:01:13 +04:00
parent 478ccf6785
commit 33940d63ca
3 changed files with 17 additions and 9 deletions

View File

@@ -120,6 +120,7 @@ export class CookieBannerClient {
try { try {
config = await fetchJSON<BannerConfig>(configUrl); config = await fetchJSON<BannerConfig>(configUrl);
} catch { } catch {
this.startDetector();
return; return;
} }
this.bannerConfig = config; this.bannerConfig = config;
@@ -324,14 +325,16 @@ export class CookieBannerClient {
this.observer = observeAndActivate(consentData, categoryLabels, texts); this.observer = observeAndActivate(consentData, categoryLabels, texts);
} }
private startDetector(config: BannerConfig): void { private startDetector(config?: BannerConfig): void {
const knownNames = new Set<string>(); const knownNames = new Set<string>();
knownNames.add(COOKIE_NAME); knownNames.add(COOKIE_NAME);
if (config) {
for (const cat of config.categories) { for (const cat of config.categories) {
for (const cookie of cat.cookies) { for (const cookie of cat.cookies) {
knownNames.add(cookie.name); knownNames.add(cookie.name);
} }
} }
}
if (this.detector) { if (this.detector) {
this.detector.stop(); this.detector.stop();

View File

@@ -13,6 +13,7 @@
// PERFORMANCE OF THIS SOFTWARE. // PERFORMANCE OF THIS SOFTWARE.
import { isDeletion, parseCookieName, parseMaxAgeSeconds } from "./cookie-utils"; import { isDeletion, parseCookieName, parseMaxAgeSeconds } from "./cookie-utils";
import { NotFoundError } from "./errors";
import { fetchJSON } from "./http"; import { fetchJSON } from "./http";
interface DetectedCookieEntry { interface DetectedCookieEntry {
@@ -140,7 +141,11 @@ export class CookieDetector {
void fetchJSON(this.reportUrl, { void fetchJSON(this.reportUrl, {
method: "POST", method: "POST",
body: { cookies: entries }, body: { cookies: entries },
}).catch(() => {}); }).catch((err) => {
if (err instanceof NotFoundError) {
this.stop();
}
});
if (this.pending.size > 0) { if (this.pending.size > 0) {
this.scheduleFlush(); this.scheduleFlush();

View File

@@ -2202,16 +2202,16 @@ func (s *Service) ReportDetectedCookies(
return s.pg.WithTx( return s.pg.WithTx(
ctx, ctx,
func(ctx context.Context, tx pg.Tx) error { func(ctx context.Context, tx pg.Tx) error {
scope := coredata.NewScopeFromObjectID(bannerID)
var banner coredata.CookieBanner var banner coredata.CookieBanner
if err := banner.LoadActiveByID(ctx, tx, bannerID); err != nil { if err := banner.LoadByID(ctx, tx, scope, bannerID); err != nil {
if errors.Is(err, coredata.ErrResourceNotFound) { if errors.Is(err, coredata.ErrResourceNotFound) {
return ErrBannerNotFound return ErrBannerNotFound
} }
return fmt.Errorf("cannot load active cookie banner: %w", err) return fmt.Errorf("cannot load cookie banner: %w", err)
} }
scope := coredata.NewScopeFromObjectID(banner.ID)
var uncategorised coredata.CookieCategory var uncategorised coredata.CookieCategory
if err := uncategorised.LoadUncategorisedByCookieBannerID(ctx, tx, scope, banner.ID); err != nil { if err := uncategorised.LoadUncategorisedByCookieBannerID(ctx, tx, scope, banner.ID); err != nil {
return fmt.Errorf("cannot load uncategorised category: %w", err) return fmt.Errorf("cannot load uncategorised category: %w", err)