From b591da92b77de638e9a1920ffc9f72297dd95068 Mon Sep 17 00:00:00 2001 From: Pete Luffman Date: Tue, 6 Jan 2026 18:37:18 +0000 Subject: [PATCH 1/2] feat: support EU data storage location in JS error reporting --- README.md | 1 + src/Plugin.php | 3 ++- src/models/Settings.php | 4 +++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a61492f..331fd77 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ return [ 'anonymous' => false, // Determines to log user info or not 'clientDsn' => getenv('SENTRY_DSN') ?: 'https://example@sentry.io/123456789', // Set as string or use environment variable. 'clientKey' => getenv('SENTRY_CLIENT_KEY') ?: 'z987654321a', // https://js.sentry-cdn.com/z987654321a.min.js + 'dataStorageLocation' => getenv('SENTRY_DATA_STORAGE_LOCATION') ?: 'US', // Can be either US or EU. Default is US if not specified 'excludedCodes' => ['400', '404', '429'], 'release' => getenv('SENTRY_RELEASE') ?: null, // Release number/name used by sentry. 'reportJsErrors' => false, diff --git a/src/Plugin.php b/src/Plugin.php index d3949b6..67bab6a 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -126,6 +126,7 @@ function (TemplateEvent $event) { $settings = $this->getSettings(); $view = Craft::$app->getView(); $ignoreErrors = json_encode($settings->ignoreErrors); + $dataStorageLocationSubdomain = $settings->dataStorageLocation == 'EU' ? 'js-de' : 'js'; $view->registerScript(" // Configure sentryOnLoad before adding the Loader Script @@ -141,7 +142,7 @@ function (TemplateEvent $event) { "", View::POS_END, array_merge([ - 'src' => "https://js.sentry-cdn.com/$settings->clientKey.min.js", + 'src' => "https://".$dataStorageLocationSubdomain.".sentry-cdn.com" ."/$settings->clientKey.min.js", 'crossorigin' => 'anonymous', ], $this->getScriptOptions()) ); diff --git a/src/models/Settings.php b/src/models/Settings.php index 11d44c5..0162a10 100644 --- a/src/models/Settings.php +++ b/src/models/Settings.php @@ -10,6 +10,7 @@ class Settings extends Model public $anonymous = false; // Determines to log user info or not public $clientDsn; public $clientKey; + public $dataStorageLocation = 'US'; public $excludedCodes = ['404']; public $release; // Release number/name used by sentry. public $reportJsErrors = false; // Client only option @@ -23,10 +24,11 @@ public function defineRules(): array { return [ [['enabled', 'anonymous', 'reportJsErrors'], 'boolean'], - [['clientDsn', 'clientKey', 'excludedCodes', 'release'], 'string'], + [['clientDsn', 'clientKey', 'excludedCodes', 'release', 'dataStorageLocation'], 'string'], [['ignoreErrors'], 'array'], [['clientDsn'], 'required'], [['sampleRate'], 'number', 'min' => 0, 'max' => 1], + [['dataStorageLocation'], 'in', 'range' => ['US', 'EU'], 'message' => 'Data Storage Location must be either "US" or "EU".'], ]; } } From a60b40d48cb3a048df5e3bb41ac6cb877140e7a0 Mon Sep 17 00:00:00 2001 From: Pete Luffman Date: Tue, 12 May 2026 18:26:33 +0100 Subject: [PATCH 2/2] feat: support for allowUrls --- README.md | 1 + src/Plugin.php | 29 +++++++++++++++++++++++++---- src/models/Settings.php | 11 ++++++----- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 331fd77..8a5212b 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ return [ 'release' => getenv('SENTRY_RELEASE') ?: null, // Release number/name used by sentry. 'reportJsErrors' => false, 'sampleRate' => 1.0, + 'allowUrls' => [], // URL string or regex. JS errors that have been created on these will be sent to Sentry. 'ignoreErrors' => [ // Email link Microsoft Outlook crawler compatibility error // cf. https://forum.sentry.io/t/unhandledrejection-non-error-promise-rejection-captured-with-value/14062 diff --git a/src/Plugin.php b/src/Plugin.php index 67bab6a..43c01ea 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -51,6 +51,12 @@ public function init() $info = $app->getInfo(); $settings = $this->getSettings(); + if(!$settings->validate()) { + Craft::error('Sentry settings are invalid: ' . json_encode($settings->getErrors()), $this->handle); + throw new Exception('Invalid Sentry plugin settings: '. json_encode($settings->getErrors())); + return; + } + if (!$this->isInstalled || !$settings->enabled) return; if (!$settings->clientDsn) { @@ -125,16 +131,31 @@ public function init() function (TemplateEvent $event) { $settings = $this->getSettings(); $view = Craft::$app->getView(); - $ignoreErrors = json_encode($settings->ignoreErrors); + + $regexMap = []; + + $allowUrls = array_map(function($url) use (&$regexMap) { + if (preg_match('/^\/(.+)\/([gimsuy]*)$/', $url, $m)) { + $key = '__REGEX_' . count($regexMap) . '__'; + $regexMap['"' . $key . '"'] = '/' . $m[1] . '/' . $m[2]; + return $key; + } + return $url; + }, $settings->allowUrls ?: []); + + $allowUrls = json_encode($allowUrls, JSON_UNESCAPED_SLASHES); + $allowUrls = str_replace(array_keys($regexMap), array_values($regexMap), $allowUrls); + $dataStorageLocationSubdomain = $settings->dataStorageLocation == 'EU' ? 'js-de' : 'js'; $view->registerScript(" // Configure sentryOnLoad before adding the Loader Script window.sentryOnLoad = function () { Sentry.init({ - release: '$settings->release', - environment: '" . App::env('CRAFT_ENVIRONMENT') . "', - ignoreErrors: $ignoreErrors, + release: '$settings->release', + environment: '" . App::env('CRAFT_ENVIRONMENT') . "', + ignoreErrors: " . json_encode($settings->ignoreErrors) . ", + allowUrls: $allowUrls }); };", View::POS_END, $this->getScriptOptions()); diff --git a/src/models/Settings.php b/src/models/Settings.php index 0162a10..3769e21 100644 --- a/src/models/Settings.php +++ b/src/models/Settings.php @@ -8,14 +8,15 @@ class Settings extends Model { public $enabled = true; public $anonymous = false; // Determines to log user info or not - public $clientDsn; - public $clientKey; + public string $clientDsn; + public string $clientKey; public $dataStorageLocation = 'US'; public $excludedCodes = ['404']; - public $release; // Release number/name used by sentry. + public string $release; // Release number/name used by sentry. public $reportJsErrors = false; // Client only option public $sampleRate = 1.0; // Client only option public $ignoreErrors = []; + public $allowUrls = []; /** * @inheritdoc @@ -24,8 +25,8 @@ public function defineRules(): array { return [ [['enabled', 'anonymous', 'reportJsErrors'], 'boolean'], - [['clientDsn', 'clientKey', 'excludedCodes', 'release', 'dataStorageLocation'], 'string'], - [['ignoreErrors'], 'array'], + [['clientDsn', 'clientKey', 'release', 'dataStorageLocation'], 'string'], + [['excludedCodes', 'ignoreErrors', 'allowUrls'], 'each', 'rule' => ['string']], [['clientDsn'], 'required'], [['sampleRate'], 'number', 'min' => 0, 'max' => 1], [['dataStorageLocation'], 'in', 'range' => ['US', 'EU'], 'message' => 'Data Storage Location must be either "US" or "EU".'],