|
81452
|
2827
|
26
|
2026-05-28T08:15:35.236604+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956135236_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$matches = $this->matchesExpectedRecipient($header->value, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedOriginalTo = explode('+', $header->value)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedOriginalTo,
]);
}
return $matches;
}
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To header', [
'message_id' => $messageId,
'headers_present' => array_map(fn ($h) => $h->name . ': ' . explode('+', $h->value)[0], $headers),
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09740692,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8374335,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"bounds":{"left":0.85272604,"top":0.019952115,"width":0.062832445,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"17","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00930851,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.006981383,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $matches = $this->matchesExpectedRecipient($header->value, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedOriginalTo = explode('+', $header->value)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedOriginalTo,\n ]);\n }\n\n return $matches;\n }\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To header', [\n 'message_id' => $messageId,\n 'headers_present' => array_map(fn ($h) => $h->name . ': ' . explode('+', $h->value)[0], $headers),\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $matches = $this->matchesExpectedRecipient($header->value, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedOriginalTo = explode('+', $header->value)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedOriginalTo,\n ]);\n }\n\n return $matches;\n }\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To header', [\n 'message_id' => $messageId,\n 'headers_present' => array_map(fn ($h) => $h->name . ': ' . explode('+', $h->value)[0], $headers),\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.7293883,"top":0.10055866,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.7390292,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.7463431,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","depth":4,"bounds":{"left":0.43051863,"top":0.09736632,"width":0.32280585,"height":0.90263367},"on_screen":true,"value":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
327918965576722946
|
-3660159508063819383
|
typing_pause
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$matches = $this->matchesExpectedRecipient($header->value, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedOriginalTo = explode('+', $header->value)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedOriginalTo,
]);
}
return $matches;
}
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To header', [
'message_id' => $messageId,
'headers_present' => array_map(fn ($h) => $h->name . ': ' . explode('+', $h->value)[0], $headers),
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
81453
|
2827
|
27
|
2026-05-28T08:15:36.886474+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956136886_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$matches = $this->matchesExpectedRecipient($header->value, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedOriginalTo = explode('+', $header->value)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedOriginalTo,
]);
}
return $matches;
}
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To header', [
'message_id' => $messageId,
'headers_present' => array_map(fn ($h) => $h->name . ': ' . explode('+', $h->value)[0], $headers),
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09740692,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8374335,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"bounds":{"left":0.85272604,"top":0.019952115,"width":0.062832445,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"17","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00930851,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.006981383,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $matches = $this->matchesExpectedRecipient($header->value, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedOriginalTo = explode('+', $header->value)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedOriginalTo,\n ]);\n }\n\n return $matches;\n }\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To header', [\n 'message_id' => $messageId,\n 'headers_present' => array_map(fn ($h) => $h->name . ': ' . explode('+', $h->value)[0], $headers),\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $matches = $this->matchesExpectedRecipient($header->value, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedOriginalTo = explode('+', $header->value)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedOriginalTo,\n ]);\n }\n\n return $matches;\n }\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To header', [\n 'message_id' => $messageId,\n 'headers_present' => array_map(fn ($h) => $h->name . ': ' . explode('+', $h->value)[0], $headers),\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.7293883,"top":0.10055866,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.7390292,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.7463431,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","depth":4,"bounds":{"left":0.43051863,"top":0.09736632,"width":0.32280585,"height":0.90263367},"on_screen":true,"value":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-2059073067913265170
|
-4200521094587332216
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$matches = $this->matchesExpectedRecipient($header->value, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedOriginalTo = explode('+', $header->value)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedOriginalTo,
]);
}
return $matches;
}
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To header', [
'message_id' => $messageId,
'headers_present' => array_map(fn ($h) => $h->name . ': ' . explode('+', $h->value)[0], $headers),
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}...
|
81452
|
NULL
|
NULL
|
NULL
|
|
81454
|
2827
|
28
|
2026-05-28T08:15:45.087226+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956145087_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$matches = $this->matchesExpectedRecipient($header->value, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedOriginalTo = explode('+', $header->value)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedOriginalTo,
]);
}
return $matches;
}
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To header', [
'message_id' => $messageId,
'headers_present' => array_map(fn ($h) => $h->name . ': ' . explode('+', $h->value)[0], $headers),
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09740692,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8374335,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"bounds":{"left":0.85272604,"top":0.019952115,"width":0.062832445,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"17","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00930851,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.006981383,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $matches = $this->matchesExpectedRecipient($header->value, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedOriginalTo = explode('+', $header->value)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedOriginalTo,\n ]);\n }\n\n return $matches;\n }\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To header', [\n 'message_id' => $messageId,\n 'headers_present' => array_map(fn ($h) => $h->name . ': ' . explode('+', $h->value)[0], $headers),\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $matches = $this->matchesExpectedRecipient($header->value, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedOriginalTo = explode('+', $header->value)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedOriginalTo,\n ]);\n }\n\n return $matches;\n }\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To header', [\n 'message_id' => $messageId,\n 'headers_present' => array_map(fn ($h) => $h->name . ': ' . explode('+', $h->value)[0], $headers),\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.7293883,"top":0.10055866,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.7390292,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.7463431,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","depth":4,"bounds":{"left":0.43051863,"top":0.09736632,"width":0.32280585,"height":0.90263367},"on_screen":true,"value":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
327918965576722946
|
-3660159508063819383
|
typing_pause
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$matches = $this->matchesExpectedRecipient($header->value, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedOriginalTo = explode('+', $header->value)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedOriginalTo,
]);
}
return $matches;
}
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To header', [
'message_id' => $messageId,
'headers_present' => array_map(fn ($h) => $h->name . ': ' . explode('+', $h->value)[0], $headers),
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
81455
|
2827
|
29
|
2026-05-28T08:15:48.546944+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956148546_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$matches = $this->matchesExpectedRecipient($header->value, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedOriginalTo = explode('+', $header->value)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedOriginalTo,
]);
}
return $matches;
}
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To header', [
'message_id' => $messageId,
'headers_present' => array_map(fn ($h) => $h->name . ': ' . explode('+', $h->value)[0], $headers),
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09740692,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8374335,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"bounds":{"left":0.85272604,"top":0.019952115,"width":0.062832445,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"17","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00930851,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.006981383,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $matches = $this->matchesExpectedRecipient($header->value, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedOriginalTo = explode('+', $header->value)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedOriginalTo,\n ]);\n }\n\n return $matches;\n }\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To header', [\n 'message_id' => $messageId,\n 'headers_present' => array_map(fn ($h) => $h->name . ': ' . explode('+', $h->value)[0], $headers),\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $matches = $this->matchesExpectedRecipient($header->value, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedOriginalTo = explode('+', $header->value)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedOriginalTo,\n ]);\n }\n\n return $matches;\n }\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To header', [\n 'message_id' => $messageId,\n 'headers_present' => array_map(fn ($h) => $h->name . ': ' . explode('+', $h->value)[0], $headers),\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.7293883,"top":0.10055866,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.7390292,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.7463431,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","depth":4,"bounds":{"left":0.43051863,"top":0.09736632,"width":0.32280585,"height":0.90263367},"on_screen":true,"value":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-1908413605128525314
|
-3732217102101747319
|
typing_pause
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$matches = $this->matchesExpectedRecipient($header->value, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedOriginalTo = explode('+', $header->value)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedOriginalTo,
]);
}
return $matches;
}
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To header', [
'message_id' => $messageId,
'headers_present' => array_map(fn ($h) => $h->name . ': ' . explode('+', $h->value)[0], $headers),
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All...
|
81454
|
NULL
|
NULL
|
NULL
|
|
81456
|
2827
|
30
|
2026-05-28T08:15:50.442577+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956150442_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$matches = $this->matchesExpectedRecipient($header->value, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedOriginalTo = explode('+', $header->value)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedOriginalTo,
]);
}
return $matches;
}
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To header', [
'message_id' => $messageId,
'headers_present' => array_map(fn ($h) => $h->name . ': ' . explode('+', $h->value)[0], $headers),
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09740692,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8374335,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"bounds":{"left":0.85272604,"top":0.019952115,"width":0.062832445,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"17","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00930851,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.006981383,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $matches = $this->matchesExpectedRecipient($header->value, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedOriginalTo = explode('+', $header->value)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedOriginalTo,\n ]);\n }\n\n return $matches;\n }\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To header', [\n 'message_id' => $messageId,\n 'headers_present' => array_map(fn ($h) => $h->name . ': ' . explode('+', $h->value)[0], $headers),\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $matches = $this->matchesExpectedRecipient($header->value, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedOriginalTo = explode('+', $header->value)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedOriginalTo,\n ]);\n }\n\n return $matches;\n }\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To header', [\n 'message_id' => $messageId,\n 'headers_present' => array_map(fn ($h) => $h->name . ': ' . explode('+', $h->value)[0], $headers),\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.7293883,"top":0.10055866,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.7390292,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.7463431,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","depth":4,"bounds":{"left":0.43051863,"top":0.09736632,"width":0.32280585,"height":0.90263367},"on_screen":true,"value":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-6234231735877047162
|
-4200521094587332216
|
typing_pause
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$matches = $this->matchesExpectedRecipient($header->value, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedOriginalTo = explode('+', $header->value)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedOriginalTo,
]);
}
return $matches;
}
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To header', [
'message_id' => $messageId,
'headers_present' => array_map(fn ($h) => $h->name . ': ' . explode('+', $h->value)[0], $headers),
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
81457
|
2826
|
21
|
2026-05-28T08:15:51.274643+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956151274_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-7635200922161528077
|
-4598385934329243181
|
typing_pause
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴2-zshscreenpipe"Digest:sha256:d6b7ebd9b71c0480b909d77fceada3df720c6594e4c853228765509b36f52db6Status: Imageis up todate for 438740370364.dkr.ecr.us-east-2.amazonaws.com/jiminny/app/q438740370364.dkr.ecr.us-east-2.amazonaws.com/jiminny/app/qa:arm64v8-latestWhat's next:View a summary of image vulnerabilities and recommendations → docker scoutquickviewlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20915-fix-missing-header-text-docker exec -it docker_lamp_1 ./vendor/bin/php-cs-fixer fix--config=.php-cs-fixer.dist.plPHP CS Fixer 3.95.1 Adalbertus by Fabien Potencier, Dariusz Ruminskiand contributors.PHP runtime: 8.5.5Loadedconfigdefault from ".php-cs-fixer.dist.php"Running analysis on 7cores with 10files per process.5698/5698100%1) app/Services/Mail/TextRelayService.php (statement_indentation)begin diff/home/jiminny/app/Services/Mail/TextRelayService.php+++/home/jiminny/app/Services/Mail/TextRelayService.php-67,7 +67,7 @eSjob = new EmailTextRelay(SmessageId, SrelayedText);Sjob-›onQueue(Constants: :QUEUE_EMAILS);dispatch($job);dispatch($job);Log: :info(' [TextRelayService]Successfully dispatched message', ["message_id'= SmessageId,end diffFixed 1 of 5698 files in 84.046 seconds, 701.18 MBmemory usedDetected deprecations in use (they will stop working in next major release)- Rule set"@PHP74Migration" is deprecated. Use"@PHP7x4Migration"instead.- Rule set "@PHP80Migration" is deprecated. Use "@PHP8x®Migration" instead.- Rule set "@PHP81Migration" is deprecated. Use "@PHP8x1Migration" instead.- Rule set "@PHP82Migration" is deprecated. Use "@PHP8x2Migration" instead.- Rule set "@PHP83Migration" is deprecated. Use "@PHP8x3Migration"instead.- Rule set "@PHP84Migration" is deprecated. Use "@PHP8x4Migration" instead.What's next:Try Docker Debug for seamless, persistent debugging tools in any containeror image »Learn more at https://docs.docker.com/go/debug-cli/lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20915-fix-missing-header-text-• •HomeDMsActivityFilesLater..•More+ED→Jiminny... vw Starrea& platform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday# jbu-team-info# jiminny-bg# platform-tickets# product_launches# random# releases# support# thank-yous# the_people_of_jimi...• Direct messages& Petko Kashinski% Galya Dimitrova&. Stefka Stoyanova: Todor StamatovStalivan Ganraiou100% <78• Thu 28 May 11:15:51Describe what you are looking for* & platform-inner-team& 106 0• MessagesP Channel OverviewMore v+Yesterday ~Resolve rrir v.oiotPreview in SlackStatusBacklogPriority= MediumAssigneeUnassignedAs of yesterday at 6:20 PM RefreshOpen in Jira*+ SummarizeToday ~NewNikolay Nikolov 10:52 AMФикс за пускане на remote commands за staging:https://github.com/jiminny/app/pull/12132#12132 Fix stage profile for remote commandsrunJIRA: JY-XXXXDeployment notes:• NoneComments1V1jiminny/app| May 26th Added by GitHubMessage & platform-inner-team...
|
81450
|
NULL
|
NULL
|
NULL
|
|
81458
|
2827
|
31
|
2026-05-28T08:15:51.476969+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956151476_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09740692,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8374335,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"bounds":{"left":0.85272604,"top":0.019952115,"width":0.062832445,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-4060176888399009113
|
-9212323791225028208
|
typing_pause
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
PhpStormViewNeweNNCCoocKetuciolool.WindowFV faVsco.|s ~$2 JY-20915-fix-missing-header-text-relaproideta Kemnelonip© SyncMailbox.phpWockhrhta© InternetMessagelnterface.ph© MailChannelService.phgTextRelayServiceTest.phpo Textrelkysewice.on0 MeetinaGeneratoomcadonên OAuth2Dn Playbooks178—KeCaLAJotaeoDn Streamingla Teama Telechony#UserPilotWebhookC Abstrac Semvice cho©ActivityProviderFactory.php© ActivityService.php© ApiResponseService.oho187188189190Ceonarsneasaries oodg InsightSeatService.phpC InstantMeetingService.phgcilntecomswneoeC IpapiClient.php© IpapiService.phpC ParticipantShareService.phg©. PlanhatService.php© PlaybackService.phpPlaybackVideoOnlyService.pho© PlaybookCategoryService.php© PlaylistGeneratorinterface.php© ResolveTeamCrmConnection.ph© SimoleThrottleService.ohdC SlackService.ohoC SocialAccountService.ohoC SoftPhoneService.oho19319419S ©) TeamOwnerService.ohoC) TeamService.oho213C) TranscodeParameterResolver.o 215C UserSemce.onC Uuidloho> M Traitc› @ UseCasesiMusAUtils>E Va cation215218Mo halnore nhr@ tnitislGrantondGtnto nhoeillliminnv nhnA Olen nhí3.env.productionclass TextRelayServiceivare tuncczon asroncurehichvarohaehtsercoousens nos morooreoox.hesodsmesshad->aerP.w.ondiol->oc-headeneorheaders as Sheader) 1eader->name === "X-6n-0riginal-To')tatches=Sthis->natchessxnectedPecsinent/SheaderswallueSexoectedAbias.Sexoecterhostr((!Smatches) ?Sanitize PIl by renoving plus-tag content for loggingSsanitizedOriginalto = explode( separator: *+*, Sheader->value)(0)=Log::info( message:' TextRelayService) Refused message','message id' => Snessageid,'original to sanitized' a› SsanitizedoriginaltoI):nol messase:Tex kelayservice Kerused nessace: eissing x-on-Urzoznal-To headen"oc10 = Snessagclorspresent' => array_nap(fn (Sh) => Sh->nane . *:• . explode( separator: *+*. Sh->value)(e A(messaoe: "[TextRelavServicel Failed to insoect ressaac*. flge_id' => Smessageldtion' = Se->aetMessageo)anwure syceor lone"atchesExpectedReciplent(string Sreciplent, string SexpectedAlias, string SexpectedHost: bool...1 edit+v Accept Fle x- X Reject File ox cSF fiminny@localhost)HS.Jocal jiminny@blocalhost)2826-85-28 87:47:501 Local.INF0: Sparansnzscorylypes = nessageaddeestartHistoryId) => 359921correlazon1d:YaC0//105-c215-4442-8886-72698253309017826-85-28 87:47:58 Local.wFu: Snessagchzscory& console [PROD)& console (EU1d":*87f39623-3deb-4827-a8cf-b862acc93289*}trace10: [CREDIT_CARD]-a8cт-0862aec93789-%17876-85528 87-S8857omuotfteSoamaneIhistorylypes => messageAddecstartHistorytoll50%2"correlation_id":"ebf74306-735e-472b-b788-f9a7f56e4655*,"trace_1d":"b2a98e4e-d669-4C84-b1de-843cecc6a681*)2826-85-28 87-58-5811 JocnlTWEn: Snessadels stomEconnelatton Saw."ehf71z0h-775a.170h-h780.40.7456e01550 "tлaCA S/.-6290R0/9-1640-hc04-h1de-9/3cecchaf91»)2924-85.28 87-55-17 | 1o601 TNEh• SoananshistoryTypes => messageAddecAwAtU&AtAAuTAl = 26002-4d4a-b84b-a8531ca414a7"1300x.06.29 92.66-17 1 1oc0-051: Snossaachstom."correlation_id":"25971837-3161-431b-adS9-e898eb48bASf* *trace_id*:*c3463c2c-d21b-4d4a-b84b-a8531ca414a7*}(2826-85-28 88:88:531 Zocal, INF0: Sparansmistorvivoes => messageaddedistartHistorvidl s 350925connel atson o""naosynoo%ctheyerark -chn chcoaiieuooace aeuei aioowe ser.oSec-hsyiuhichthuOierhoR RRohieSaioetst Srassadelsrom#[CREDIT_CARD].05cc-H529269c24h7"2924-85-28 AR-95-27| Toeol TNSh: Soananeanler herseietS0100% 142-• Thu 28 May 11:15:51TextRelayServiceTest+0.Winat about thit. Saeme the a sion ie in cmall. Witistill work and howaAsk anything (XOL)—@ eodeAdhotvAReinctalAccoot allXwodeurlhimewrekhirest4 space...
|
81456
|
NULL
|
NULL
|
NULL
|
|
81459
|
2827
|
32
|
2026-05-28T08:16:04.643710+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956164643_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$matches = $this->matchesExpectedRecipient($header->value, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedOriginalTo = explode('+', $header->value)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedOriginalTo,
]);
}
return $matches;
}
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To header', [
'message_id' => $messageId,
'headers_present' => array_map(fn ($h) => $h->name . ': ' . explode('+', $h->value)[0], $headers),
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09740692,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8374335,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"bounds":{"left":0.85272604,"top":0.019952115,"width":0.062832445,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"17","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00930851,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.006981383,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $matches = $this->matchesExpectedRecipient($header->value, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedOriginalTo = explode('+', $header->value)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedOriginalTo,\n ]);\n }\n\n return $matches;\n }\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To header', [\n 'message_id' => $messageId,\n 'headers_present' => array_map(fn ($h) => $h->name . ': ' . explode('+', $h->value)[0], $headers),\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $matches = $this->matchesExpectedRecipient($header->value, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedOriginalTo = explode('+', $header->value)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedOriginalTo,\n ]);\n }\n\n return $matches;\n }\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To header', [\n 'message_id' => $messageId,\n 'headers_present' => array_map(fn ($h) => $h->name . ': ' . explode('+', $h->value)[0], $headers),\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.7293883,"top":0.10055866,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.7390292,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.7463431,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","depth":4,"bounds":{"left":0.43051863,"top":0.09736632,"width":0.32280585,"height":0.90263367},"on_screen":true,"value":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
327918965576722946
|
-3660159508063819383
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$matches = $this->matchesExpectedRecipient($header->value, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedOriginalTo = explode('+', $header->value)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedOriginalTo,
]);
}
return $matches;
}
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To header', [
'message_id' => $messageId,
'headers_present' => array_map(fn ($h) => $h->name . ': ' . explode('+', $h->value)[0], $headers),
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
81460
|
2826
|
22
|
2026-05-28T08:16:23.558532+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956183558_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.02111111},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"17","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.019444445,"height":0.02111111},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.025555555},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.014583333,"height":0.025555555},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
7456676975688765609
|
-6438878488507806805
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
81461
|
2826
|
23
|
2026-05-28T08:16:25.691166+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956185691_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴2-zshscreenpipe"Digest:sha256:d6b7ebd9b71c0480b909d77fceada3df720c6594e4c853228765509b36f52db6Status: Imageis up todate for 438740370364.dkr.ecr.us-east-2.amazonaws.com/jiminny/app/q438740370364.dkr.ecr.us-east-2.amazonaws.com/jiminny/app/qa:arm64v8-latestWhat's next:View a summary of image vulnerabilities and recommendations → docker scoutquickviewlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20915-fix-missing-header-text-docker exec -it docker_lamp_1 ./vendor/bin/php-cs-fixer fix--config=.php-cs-fixer.dist.plPHP CS Fixer 3.95.1 Adalbertus by Fabien Potencier, Dariusz Ruminskiand contributors.PHP runtime: 8.5.5Loadedconfigdefault from ".php-cs-fixer.dist.php"Running analysis on 7cores with 10files per process.5698/5698100%1) app/Services/Mail/TextRelayService.php (statement_indentation)begin diff/home/jiminny/app/Services/Mail/TextRelayService.php+++/home/jiminny/app/Services/Mail/TextRelayService.php-67,7 +67,7 @eSjob = new EmailTextRelay(SmessageId, SrelayedText);Sjob-›onQueue(Constants: :QUEUE_EMAILS);dispatch($job);dispatch($job);Log: :info(' [TextRelayService]Successfully dispatched message', ["message_id'= SmessageId,end diffFixed 1 of 5698 files in 84.046 seconds, 701.18 MBmemory usedDetected deprecations in use (they will stop working in next major release)- Rule set"@PHP74Migration" is deprecated. Use"@PHP7x4Migration"instead.- Rule set "@PHP80Migration" is deprecated. Use "@PHP8x®Migration" instead.- Rule set "@PHP81Migration" is deprecated. Use "@PHP8x1Migration" instead.- Rule set "@PHP82Migration" is deprecated. Use "@PHP8x2Migration" instead.- Rule set "@PHP83Migration" is deprecated. Use "@PHP8x3Migration"instead.- Rule set "@PHP84Migration" is deprecated. Use "@PHP8x4Migration" instead.What's next:Try Docker Debug for seamless, persistent debugging tools in any containeror image »Learn more at https://docs.docker.com/go/debug-cli/lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20915-fix-missing-header-text-• •HomeDMsActivityFilesLater..•More+ED→Jiminny... vw Starrea& platform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday# jbu-team-info# jiminny-bg# platform-tickets# product_launches# random# releases# support# thank-yous# the_people_of_jimi...• Direct messages& Petko Kashinski% Galya Dimitrova&. Stefka Stoyanova: Todor StamatovStalivan Ganraiou100% <78• Thu 28 May 11:16:25Describe what you are looking for* & platform-inner-team& 106 0• MessagesP Channel OverviewMore v+Yesterday ~Resolve rrir v.oiotPreview in SlackStatusBacklogPriority= MediumAssigneeUnassignedAs of yesterday at 6:20 PM RefreshOpen in Jira*+ SummarizeToday ~NewNikolay Nikolov 10:52 AMФикс за пускане на remote commands за staging:https://github.com/jiminny/app/pull/12132#12132 Fix stage profile for remote commandsrunJIRA: JY-XXXXDeployment notes:• NoneComments1V1jiminny/app| May 26th Added by GitHubMessage & platform-inner-team...
|
NULL
|
1854427488783385704
|
NULL
|
click
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴2-zshscreenpipe"Digest:sha256:d6b7ebd9b71c0480b909d77fceada3df720c6594e4c853228765509b36f52db6Status: Imageis up todate for 438740370364.dkr.ecr.us-east-2.amazonaws.com/jiminny/app/q438740370364.dkr.ecr.us-east-2.amazonaws.com/jiminny/app/qa:arm64v8-latestWhat's next:View a summary of image vulnerabilities and recommendations → docker scoutquickviewlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20915-fix-missing-header-text-docker exec -it docker_lamp_1 ./vendor/bin/php-cs-fixer fix--config=.php-cs-fixer.dist.plPHP CS Fixer 3.95.1 Adalbertus by Fabien Potencier, Dariusz Ruminskiand contributors.PHP runtime: 8.5.5Loadedconfigdefault from ".php-cs-fixer.dist.php"Running analysis on 7cores with 10files per process.5698/5698100%1) app/Services/Mail/TextRelayService.php (statement_indentation)begin diff/home/jiminny/app/Services/Mail/TextRelayService.php+++/home/jiminny/app/Services/Mail/TextRelayService.php-67,7 +67,7 @eSjob = new EmailTextRelay(SmessageId, SrelayedText);Sjob-›onQueue(Constants: :QUEUE_EMAILS);dispatch($job);dispatch($job);Log: :info(' [TextRelayService]Successfully dispatched message', ["message_id'= SmessageId,end diffFixed 1 of 5698 files in 84.046 seconds, 701.18 MBmemory usedDetected deprecations in use (they will stop working in next major release)- Rule set"@PHP74Migration" is deprecated. Use"@PHP7x4Migration"instead.- Rule set "@PHP80Migration" is deprecated. Use "@PHP8x®Migration" instead.- Rule set "@PHP81Migration" is deprecated. Use "@PHP8x1Migration" instead.- Rule set "@PHP82Migration" is deprecated. Use "@PHP8x2Migration" instead.- Rule set "@PHP83Migration" is deprecated. Use "@PHP8x3Migration"instead.- Rule set "@PHP84Migration" is deprecated. Use "@PHP8x4Migration" instead.What's next:Try Docker Debug for seamless, persistent debugging tools in any containeror image »Learn more at https://docs.docker.com/go/debug-cli/lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20915-fix-missing-header-text-• •HomeDMsActivityFilesLater..•More+ED→Jiminny... vw Starrea& platform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday# jbu-team-info# jiminny-bg# platform-tickets# product_launches# random# releases# support# thank-yous# the_people_of_jimi...• Direct messages& Petko Kashinski% Galya Dimitrova&. Stefka Stoyanova: Todor StamatovStalivan Ganraiou100% <78• Thu 28 May 11:16:25Describe what you are looking for* & platform-inner-team& 106 0• MessagesP Channel OverviewMore v+Yesterday ~Resolve rrir v.oiotPreview in SlackStatusBacklogPriority= MediumAssigneeUnassignedAs of yesterday at 6:20 PM RefreshOpen in Jira*+ SummarizeToday ~NewNikolay Nikolov 10:52 AMФикс за пускане на remote commands за staging:https://github.com/jiminny/app/pull/12132#12132 Fix stage profile for remote commandsrunJIRA: JY-XXXXDeployment notes:• NoneComments1V1jiminny/app| May 26th Added by GitHubMessage & platform-inner-team...
|
81460
|
NULL
|
NULL
|
NULL
|
|
81462
|
2827
|
33
|
2026-05-28T08:16:25.794078+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956185794_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
rapstomCoocWindowFV faVsco.s ~$ JY-20915-fix-missi rapstomCoocWindowFV faVsco.s ~$ JY-20915-fix-missing-header-text-© InternetMessagelnterface.ph© MailChannelService.phg0 MeetinaGeneratoromcadonEOHUNDn PlaybooksJotaeoa Teama Telechony#UserPilotWebhookC Abstrac Semvice cho©ActivitvProviderFactory.oho© ActivityService.php© ApiResponseService.ohoCeonarsneasaries oodg InsightSeatService.phpC InstantMeetingService.phpcilntecomswneoeC IpapiClient.php© IpapiService.phpC ParticipantShareService.phg©. PlanhatService.php© PlaybackService.phpPlaybackVideoOnlyService.pho© PlaybookCategoryService.php© PlaylistGeneratorinterface.phpel PocAlvoTosmErmEmЛodiA ny© SimoleThrottleService.ohg© SlackService.ohdC SocialAccountService.oho)C SoftPhoneService.oho©) TeamOwnerService.ohoC) TeamService.ohoC) TranscodeParameterResolver.ohC UserSemce.on©Uuid.php> M Traitc@ UseCasese ValaationMo halnore nhr@ tnitislGrantondGtnto nhoelliminnv nhamockhrhtsTextRelayServiceTest.php3.env.productionclass TextRelayServiceouoere Tuncczon syne diidAAAAUIUTTTASSnazloox & contzol xeyanny,coogle texc userSexpectedAlias = config(key. 'jiminny.deploy region') =a= 'eu' ? "catch-all-eu' : 'catch-all''(TextRelavSeryicel Stanttina svnc'."MexoeCro mous EXSeXoeCeohee>exoccreohosSsenwice e Sthis->ae-Semuicetstaslbox)SmessageHistory = Sthis->getHistory(Sservice):aulunznace suopore racades Loa::channel-cuscon channel ->intolSnessagchase AcceotSmessageIds = 0:foreach (SnessageHistory as Shistories) {Snessages = Shistories->messagesAdded ?? 0:foreach (Smessages as Smessage)Snessageld = Smessage-snessage->idif ( Sthis->isForQurrentEnvironnent(Sservice, Snallbox, Snessageld, SexoectedAlias.Norowoeroesss0eosrsosSf (ScelavedText === null)ScelavedText = TextRelave:createrfemaa orouidert e> Texthelay.eproumer ostare"emaennouider o s> Shesssoeld.satus' E Textee hy.STATS PRodEsSiNGSiob = new Emai TextRelay(Snessageld, Srelayediext):ahesonthouoteuCanctanternEit MATGoeon chil100dispatch(Siob):Loo:sinfo( messace: "(TextRelavService) Successfully dispatched nessage"nessago id/ pa snsse ice na xaX Reject File oxesr uim nnye rocolnost& console [PROD# consoe leu.cozo"os"lo 01.4/.00 Locat.nr. godidushistoryTypes => messageAddec(startHistoryId) => 359921correlazon1d:YaC0//105-c215-4442-2886-7269823580901trace_1d*: *87f39623-3deb-4827-a8cf-b862aec93289**7826-85-28 87:47:58 Local.IWFU: SnessagchzscomvoTrace10: [CREDIT_CARD]-a8cт-0862aec93789-17876-85528 87-S8857omuotfteSoamaneIhistorylypes => messageAddecstartHistorytoll50%2{"correlation_id":"ebf74386-735e-472b-b788-f9a7f56e4655*,*trace_1d*:"b2a98e4e-d669-4c84-b1de-843cecc6a681")2826-85-28 R7-59-5811 1oclTNED: Snessadels stomuEconnelatton Saw."ehf71z0h-775a.170h-h780.40.7456e01550 "ьласA S/.-6290R0/9-1640-6604-h1de-9/3cecchaf91»)2924-85.28 87-55-17 | 1o601 TNEh• SoananshistoryTypes => messageAddecAwAtU&AtAAuTAl = 26002-4d4a-b84b-a8531ca414a7"1300x.06.2992-66-17| Jocol-Twet: Snossagchs stom.#"correlation_id":"25971837-3161-431b-adS9-e898eb49beSf*, *trace_1d*:*c3463c2c-d21b-4d4a-b84b-a8531ca614a7"}(2826-85-28 88:88:531 Zocal, INF0: Sparansmistorvnvoes => nessagenddedistartHistorvidl s 350925connel atson o""naosynoo%ctheyerark -chn chcoaiieuooace aeuei aioowe ser.oSec-hsyiuhichthuOierhoR RRohieSaioetst Srassadelsrom#[CREDIT_CARD].05cc-H529269c24h7"2924-85-28 AR-95-27| Toeol TNSh: Soananeoo inu co moy tirloiceeeendhOTXCONHENYSWWIC+0.Winst about the. Shams the + cion is in emslWitistill work and hownYes, this will work correctly. Let me trace through the logic with this exact ema:oneioerwilue carchswe/woL7o0orsshoobl.rdowkhtwer1ohnnv.co0 pho11 1. Split on €oirdeccheateeobewtonehoturdos kolotorxrwehtnnv.cos"I1 2. Host check: 'txt.fiminny.com"11 3. Strip plus tag fron local partcatch-all[PHONE]..11 - 'catch-all/1 4. Compare alías: 'catch-all' mm 'catch-all' - returns truSo isForcurrentEnvi ronsentl returns true and the messade orocreos to be disoatchedThen in EnaflTextRelay job, parseRecipient() uses the To header directly and the regex \d+\.1d+\. [a-zA-20-- the + prefixoetore tne phone numoers is stipped or parschecipientintoentities, wiich prepenos + iselt anyway.Everythina worke end-tosand. Now vou luet nesd to ranodly the To Thoader thinrck ir so these mosenaosaren't refused.vice.pho #L182-210haytRelusarich.oor1tile +24-15>Ask anything (XOL)" HodhAdhotvAcceot all• OKwindeurlahmeht4 spad...
|
NULL
|
6843649552266690491
|
NULL
|
click
|
ocr
|
NULL
|
rapstomCoocWindowFV faVsco.s ~$ JY-20915-fix-missi rapstomCoocWindowFV faVsco.s ~$ JY-20915-fix-missing-header-text-© InternetMessagelnterface.ph© MailChannelService.phg0 MeetinaGeneratoromcadonEOHUNDn PlaybooksJotaeoa Teama Telechony#UserPilotWebhookC Abstrac Semvice cho©ActivitvProviderFactory.oho© ActivityService.php© ApiResponseService.ohoCeonarsneasaries oodg InsightSeatService.phpC InstantMeetingService.phpcilntecomswneoeC IpapiClient.php© IpapiService.phpC ParticipantShareService.phg©. PlanhatService.php© PlaybackService.phpPlaybackVideoOnlyService.pho© PlaybookCategoryService.php© PlaylistGeneratorinterface.phpel PocAlvoTosmErmEmЛodiA ny© SimoleThrottleService.ohg© SlackService.ohdC SocialAccountService.oho)C SoftPhoneService.oho©) TeamOwnerService.ohoC) TeamService.ohoC) TranscodeParameterResolver.ohC UserSemce.on©Uuid.php> M Traitc@ UseCasese ValaationMo halnore nhr@ tnitislGrantondGtnto nhoelliminnv nhamockhrhtsTextRelayServiceTest.php3.env.productionclass TextRelayServiceouoere Tuncczon syne diidAAAAUIUTTTASSnazloox & contzol xeyanny,coogle texc userSexpectedAlias = config(key. 'jiminny.deploy region') =a= 'eu' ? "catch-all-eu' : 'catch-all''(TextRelavSeryicel Stanttina svnc'."MexoeCro mous EXSeXoeCeohee>exoccreohosSsenwice e Sthis->ae-Semuicetstaslbox)SmessageHistory = Sthis->getHistory(Sservice):aulunznace suopore racades Loa::channel-cuscon channel ->intolSnessagchase AcceotSmessageIds = 0:foreach (SnessageHistory as Shistories) {Snessages = Shistories->messagesAdded ?? 0:foreach (Smessages as Smessage)Snessageld = Smessage-snessage->idif ( Sthis->isForQurrentEnvironnent(Sservice, Snallbox, Snessageld, SexoectedAlias.Norowoeroesss0eosrsosSf (ScelavedText === null)ScelavedText = TextRelave:createrfemaa orouidert e> Texthelay.eproumer ostare"emaennouider o s> Shesssoeld.satus' E Textee hy.STATS PRodEsSiNGSiob = new Emai TextRelay(Snessageld, Srelayediext):ahesonthouoteuCanctanternEit MATGoeon chil100dispatch(Siob):Loo:sinfo( messace: "(TextRelavService) Successfully dispatched nessage"nessago id/ pa snsse ice na xaX Reject File oxesr uim nnye rocolnost& console [PROD# consoe leu.cozo"os"lo 01.4/.00 Locat.nr. godidushistoryTypes => messageAddec(startHistoryId) => 359921correlazon1d:YaC0//105-c215-4442-2886-7269823580901trace_1d*: *87f39623-3deb-4827-a8cf-b862aec93289**7826-85-28 87:47:58 Local.IWFU: SnessagchzscomvoTrace10: [CREDIT_CARD]-a8cт-0862aec93789-17876-85528 87-S8857omuotfteSoamaneIhistorylypes => messageAddecstartHistorytoll50%2{"correlation_id":"ebf74386-735e-472b-b788-f9a7f56e4655*,*trace_1d*:"b2a98e4e-d669-4c84-b1de-843cecc6a681")2826-85-28 R7-59-5811 1oclTNED: Snessadels stomuEconnelatton Saw."ehf71z0h-775a.170h-h780.40.7456e01550 "ьласA S/.-6290R0/9-1640-6604-h1de-9/3cecchaf91»)2924-85.28 87-55-17 | 1o601 TNEh• SoananshistoryTypes => messageAddecAwAtU&AtAAuTAl = 26002-4d4a-b84b-a8531ca414a7"1300x.06.2992-66-17| Jocol-Twet: Snossagchs stom.#"correlation_id":"25971837-3161-431b-adS9-e898eb49beSf*, *trace_1d*:*c3463c2c-d21b-4d4a-b84b-a8531ca614a7"}(2826-85-28 88:88:531 Zocal, INF0: Sparansmistorvnvoes => nessagenddedistartHistorvidl s 350925connel atson o""naosynoo%ctheyerark -chn chcoaiieuooace aeuei aioowe ser.oSec-hsyiuhichthuOierhoR RRohieSaioetst Srassadelsrom#[CREDIT_CARD].05cc-H529269c24h7"2924-85-28 AR-95-27| Toeol TNSh: Soananeoo inu co moy tirloiceeeendhOTXCONHENYSWWIC+0.Winst about the. Shams the + cion is in emslWitistill work and hownYes, this will work correctly. Let me trace through the logic with this exact ema:oneioerwilue carchswe/woL7o0orsshoobl.rdowkhtwer1ohnnv.co0 pho11 1. Split on €oirdeccheateeobewtonehoturdos kolotorxrwehtnnv.cos"I1 2. Host check: 'txt.fiminny.com"11 3. Strip plus tag fron local partcatch-all[PHONE]..11 - 'catch-all/1 4. Compare alías: 'catch-all' mm 'catch-all' - returns truSo isForcurrentEnvi ronsentl returns true and the messade orocreos to be disoatchedThen in EnaflTextRelay job, parseRecipient() uses the To header directly and the regex \d+\.1d+\. [a-zA-20-- the + prefixoetore tne phone numoers is stipped or parschecipientintoentities, wiich prepenos + iselt anyway.Everythina worke end-tosand. Now vou luet nesd to ranodly the To Thoader thinrck ir so these mosenaosaren't refused.vice.pho #L182-210haytRelusarich.oor1tile +24-15>Ask anything (XOL)" HodhAdhotvAcceot all• OKwindeurlahmeht4 spad...
|
81459
|
NULL
|
NULL
|
NULL
|
|
81463
|
2826
|
24
|
2026-05-28T08:16:27.496999+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956187496_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-3150964534923304660
|
-4304507549388960332
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴2-zshscreenpipe"Digest:sha256:d6b7ebd9b71c0480b909d77fceada3df720c6594e4c853228765509b36f52db6Status: Imageis up todate for 438740370364.dkr.ecr.us-east-2.amazonaws.com/jiminny/app/q438740370364.dkr.ecr.us-east-2.amazonaws.com/jiminny/app/qa:arm64v8-latestWhat's next:View a summary of image vulnerabilities and recommendations → docker scoutquickviewlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20915-fix-missing-header-text-docker exec -it docker_lamp_1 ./vendor/bin/php-cs-fixer fix--config=.php-cs-fixer.dist.plPHP CS Fixer 3.95.1 Adalbertus by Fabien Potencier, Dariusz Ruminskiand contributors.PHP runtime: 8.5.5Loadedconfigdefault from ".php-cs-fixer.dist.php"Running analysis on 7cores with 10files per process.5698/5698100%1) app/Services/Mail/TextRelayService.php (statement_indentation)begin diff/home/jiminny/app/Services/Mail/TextRelayService.php+++/home/jiminny/app/Services/Mail/TextRelayService.php-67,7 +67,7 @eSjob = new EmailTextRelay(SmessageId, SrelayedText);Sjob-›onQueue(Constants: :QUEUE_EMAILS);dispatch($job);dispatch($job);Log: :info(' [TextRelayService]Successfully dispatched message', ["message_id'= SmessageId,end diffFixed 1 of 5698 files in 84.046 seconds, 701.18 MBmemory usedDetected deprecations in use (they will stop working in next major release)- Rule set"@PHP74Migration" is deprecated. Use"@PHP7x4Migration"instead.- Rule set "@PHP80Migration" is deprecated. Use "@PHP8x®Migration" instead.- Rule set "@PHP81Migration" is deprecated. Use "@PHP8x1Migration" instead.- Rule set "@PHP82Migration" is deprecated. Use "@PHP8x2Migration" instead.- Rule set "@PHP83Migration" is deprecated. Use "@PHP8x3Migration"instead.- Rule set "@PHP84Migration" is deprecated. Use "@PHP8x4Migration" instead.What's next:Try Docker Debug for seamless, persistent debugging tools in any containeror image »Learn more at https://docs.docker.com/go/debug-cli/lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20915-fix-missing-header-text-• •HomeDMsActivityFilesLater..•More+ED→Jiminny... vw Starrea& platform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday# jbu-team-info# jiminny-bg# platform-tickets# product_launches# random# releases# support# thank-yous# the_people_of_jimi...• Direct messages& Petko Kashinski% Galya Dimitrova&. Stefka Stoyanova: Todor StamatovStalivan Ganraiou100% <78• Thu 28 May 11:16:27Describe what you are looking for* & platform-inner-team& 106 0• MessagesP Channel OverviewMore v+Yesterday ~Resolve rrir v.oiotPreview in SlackStatusBacklogPriority= MediumAssigneeUnassignedAs of yesterday at 6:20 PM RefreshOpen in Jira*+ SummarizeToday ~NewNikolay Nikolov 10:52 AMФикс за пускане на remote commands за staging:https://github.com/jiminny/app/pull/12132#12132 Fix stage profile for remote commandsrunJIRA: JY-XXXXDeployment notes:• NoneComments1V1jiminny/app| May 26th Added by GitHubMessage & platform-inner-team...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
81464
|
2826
|
25
|
2026-05-28T08:16:30.508036+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956190508_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.02111111},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"17","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.019444445,"height":0.02111111},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.025555555},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.014583333,"height":0.025555555},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","depth":4,"on_screen":true,"value":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-4729423357167171668
|
-8235799205988284024
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
81463
|
NULL
|
NULL
|
NULL
|
|
81465
|
2827
|
34
|
2026-05-28T08:16:30.609585+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956190609_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09740692,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8374335,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"bounds":{"left":0.85272604,"top":0.019952115,"width":0.062832445,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"17","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00930851,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.006981383,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.7293883,"top":0.10055866,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.7390292,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.7463431,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","depth":4,"bounds":{"left":0.43051863,"top":0.09736632,"width":0.32280585,"height":0.90263367},"on_screen":true,"value":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-4729423357167171668
|
-8235799205988284024
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
81466
|
2827
|
35
|
2026-05-28T08:16:31.901746+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956191901_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09740692,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8374335,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"bounds":{"left":0.85272604,"top":0.019952115,"width":0.062832445,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"17","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00930851,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.006981383,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.7293883,"top":0.10055866,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.7390292,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.7463431,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","depth":4,"bounds":{"left":0.43051863,"top":0.09736632,"width":0.32280585,"height":0.90263367},"on_screen":true,"value":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-8364568366956037565
|
-8235816729454851704
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project...
|
81465
|
NULL
|
NULL
|
NULL
|
|
81467
|
2827
|
36
|
2026-05-28T08:16:47.307201+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956207307_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09740692,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8374335,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"bounds":{"left":0.85272604,"top":0.019952115,"width":0.062832445,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"17","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00930851,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.006981383,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.7293883,"top":0.10055866,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.7390292,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.7463431,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","depth":4,"bounds":{"left":0.43051863,"top":0.09736632,"width":0.32280585,"height":0.90263367},"on_screen":true,"value":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-4729423357167171668
|
-8235799205988284024
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
81468
|
2826
|
26
|
2026-05-28T08:16:49.793362+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956209793_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.02111111},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"17","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.019444445,"height":0.02111111},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.025555555},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
2797364124384554827
|
-7623060321892881446
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
SlackFileEditViewGoHistoryWindowHelpDOCKERO ₴1DEV (docker)₴2-zshscreenpipe"Digest:sha256:d6b7ebd9b71c0480b909d77fceada3df720c6594e4c853228765509b36f52db6Status: Imageis up todate for 438740370364.dkr.ecr.us-east-2.amazonaws.com/jiminny/app/q438740370364.dkr.ecr.us-east-2.amazonaws.com/jiminny/app/qa:arm64v8-latestWhat's next:View a summary of image vulnerabilities and recommendations → docker scoutquickviewlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20915-fix-missing-header-text-docker exec -it docker_lamp_1 ./vendor/bin/php-cs-fixer fix--config=.php-cs-fixer.dist.plPHP CS Fixer 3.95.1 Adalbertus by Fabien Potencier, Dariusz Ruminskiand contributors.PHP runtime: 8.5.5Loadedconfigdefault from ".php-cs-fixer.dist.php"Running analysis on 7cores with 10files per process.5698/5698100%1) app/Services/Mail/TextRelayService.php (statement_indentation)begin diff/home/jiminny/app/Services/Mail/TextRelayService.php+++/home/jiminny/app/Services/Mail/TextRelayService.php-67,7 +67,7 @eSjob = new EmailTextRelay(SmessageId, SrelayedText);Sjob-›onQueue(Constants: :QUEUE_EMAILS);dispatch($job);dispatch($job);Log: :info(' [TextRelayService]Successfully dispatched message', ["message_id'= SmessageId,end diffFixed 1 of 5698 files in 84.046 seconds, 701.18 MBmemory usedDetected deprecations in use (they will stop working in next major release)- Rule set"@PHP74Migration" is deprecated. Use"@PHP7x4Migration"instead.- Rule set "@PHP80Migration" is deprecated. Use "@PHP8x®Migration" instead.- Rule set "@PHP81Migration" is deprecated. Use "@PHP8x1Migration" instead.- Rule set "@PHP82Migration" is deprecated. Use "@PHP8x2Migration" instead.- Rule set "@PHP83Migration" is deprecated. Use "@PHP8x3Migration"instead.- Rule set "@PHP84Migration" is deprecated. Use "@PHP8x4Migration" instead.What's next:Try Docker Debug for seamless, persistent debugging tools in any containeror image »Learn more at https://docs.docker.com/go/debug-cli/lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20915-fix-missing-header-text-• •HomeDMsActivityFilesLater..•More+ED→Jiminny... vw Starrea& platform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday# jbu-team-info# jiminny-bg# platform-tickets# product_launches# random# releases# support# thank-yous# the_people_of_jimi...• Direct messages& Petko Kashinski% Galya Dimitrova&. Stefka Stoyanova: Todor StamatovStalivan Ganraiou100% <78• Thu 28 May 11:16:49Describe what you are looking for®* & platform-inner-team& 106 0• MessagesP Channel OverviewMore v+Yesterday ~Resolve rrir v.oiotPreview in SlackStatusBacklogPriority= MediumAssigneeUnassignedAs of yesterday at 6:20 PM RefreshOpen in Jira*+ SummarizeToday ~NewNikolay Nikolov 10:52 AMФикс за пускане на remote commands за staging:https://github.com/jiminny/app/pull/12132#12132 Fix stage profile for remote commandsrunJIRA: JY-XXXXDeployment notes:• NoneComments1V1jiminny/app| May 26th Added by GitHubMessage & platform-inner-team...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
81469
|
2827
|
37
|
2026-05-28T08:16:49.898635+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956209898_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09740692,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-3150964534923304660
|
-4304507549388960332
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
PhpStormViewCootRurTOOI-WindowFV faVsco.|s ~$ JY-20915-fix-misproidet) Kernelphp© SyncMailbox.phpockhrhtt© InternetMessagelnterface.ph© MailChannelService.phgTextRelayServiceTest.php3.env.productionclass TextRelayServiceo Textrelkysewice.ond MeetingGeneratorda Notificationên OAuth2in Playbooks—KeCaLA—oeownyJ StrategyStreaminga Teama [EMAIL]@ ApiResponseService.ohdCeonarsneasaries oodclineehCaatswies donC InstantMeetingService.phgc IntercomService.phgC IpapiClient.phpc lpapiService.phpC ParticipantShareService.phg© PlanhatService.php© PlaybackService.phpPlaybackVideoOnlyService.pho© PlaybookCategoryService.php© PlaylistGeneratorinterface.php© ResolveTeamCrmConnection.ph© SimoleThrottleService.ohd© SlackService.oho© SoclalAccountService.oho)© SoftPhoneService.oho©) TeamDeactivatedService.oho©) TeamOwnerService.ohoC) TeamService.ohoC) TranscodeParameterResolver.ohCUserService.ohdC Uuidloho> M Traitc@ UseCases181182183uuise ValaationMo halnore nhr@ tnitislGrantondGtnto nho88555852553eillliminnv nhnA Olen nhipobtaeatuuetzondaueysnscogyroangeyeegne seoezeee. 12sservace & schis-serservace suazlooxSwatchRequest = new Google6naiz\WatchRequestoSwatchRequest->setLabelIds(['INB0X'])smechkeoues csstthewecnterwrconcluotSexonrunhisdino= SwatchResponse->expiration / 1000;ShistoryPosint =ointl SwarcheesoonseoshictomydSthis->setHistoryPoint(Stopic, ShistoryPoint);return ShistoryPoint;private function isForCurrentEnvironmentGoogleGnail Sserviceetasnn Chasihaystring SexpectedAliasstring SexpectedHos:): boor ttoy lSnessage = Sservice->users nessages->get(Smailbox, Smessageld)sheaders = saessage->oexrayload ->oecheadersorSoniginalTo = null;Rencetforeach (Sheaders as Sheader)Sif (Sheaden->nane aa= «X-6n-0cfoinal-To") 2Smatches = Sthis->natchesExpectedRecipient(Sheader->value, SexpectedALias.} elseif (Sheader->name aa= 'To') 4nethandon.susimeeSrecipient = Soriginalto ?? Sto:if (Srecipient !as nulb)Snatches = Sthis->matchesExpectedRecipient(Srecipient, SexpectedALias, SexpectedHostv Accept Fle x- X Reject File ox ci4 CnatchesiSF (iminny@localhost)HS.Jocal jiminny@blocalhost)& console [PROD)# consoe leu.2826-85-28 87:47:501 Local.INF0: Sparansnzscorylypes = messageaddecstartHistoryId) => 3599219aC0 //105-02715-4442-3886-12638233809701d":*87f39623-3deb-4827-aBcf-b862acc93289**17826-85-28 87:47:58 Local.wFu: Snessagchzscorytrace10: [CREDIT_CARD]-a8cт-0862aec93789-%17876-85528 87-S8857omuotfteSoamaneIhistorylypes => messageAddecstartHistorytoll50%2*ebf74306-735e-472b-b788-f9a7f56e4655*, "trace_1d":"b2a98e4e-d669-4c84-b1de-843cecc6а681*)2826-85-28 87-58-5811 JocnlTWEn: Snessadels stom{"correlation_id":"ebf74306-735e-472b-b788-f9a7f56e4655*,"trace_1d":"b2a98e4e-d669-4C04-b1de-843cecc6a681"}2924-05.28 87-55-17 1 1oc01 TNSh: SoananshistoryTypes => messageAddecAwAtU&AtAAuTAl = 26002-4d4a-b84b-a8531ca414a7"12826-85-28 87:55:171 Zocal.INF0: SmessageHistory#"correlation_id":"25971837-3141-431b-adS9-e898eb49beSf*, *trace_1d*:*c3463c2c-d21b-4d4a-b84b-a8531ca414a7"}(2826-85-28 88:88:531 Zocal, INF0: SparansArrav[historyTypesl => nessageAddedistartHistoruidl s 350029connel atson o""naosynoo%ctheyerark -chn chcoaiieuooace aeuei aioowe ser.oSec-hsyiuhichthuOierhoR RRohieSaioetst SrassadelsromX6c82479-7042-1566.05cc-h529269c24h7m2924-85.28 9R-95-271 1ocol TМSЛ• Soananeinu cowoy ti-lo.Cascadirner hensewiet+0.Winst about the. Shams the + cion is in emslWitistill work and hownYes, this will work correctly. Let me trace through the logic with this exact ema:oneioerwawue carchswewwoL720onsshwobl.n0o.ktw1oinnv.cos0 pho11 1. Split on €oirdecch- tuewbewtonsehototordoskolotorxrwetnnv.con"I1 2. Host check: 'txt.fiminny.com'11 3. Strip plus tag fron local partcatch-all[PHONE]...e- "catch-all/1 4. Compare alías: 'catch-all' mm 'catch-all' - returns truSo isForcurrentEnvi ronsentü returns true and the messade orocreds to be disoatchedThen in EnaflTextRelay job, parseRecipient() uses the To header directly and the regex \d+\.1d+\. [a-zA-20-- the + prefixoetore tne phone numoers is stipped or parschecipientintoentities, wiuch prepenos + iselt anyway.Everythina worke end-tosand. Now vou luet nesd to ranodly the To Thoader thinrck ir so these mosenaosaren't refused.pho #L182-218haytRelusarich.oorFix is back in place and the temporary headerspresent disgnostic logging is removed. The tests already reflectthis loae trom aartar. Youtre cnodito deoio1tile +23-12>Ask anything (XOL)- @ CodnAdhotvAcceot allKwindeurlahmest4 space...
|
81467
|
NULL
|
NULL
|
NULL
|
|
81470
|
2827
|
38
|
2026-05-28T08:16:51.859578+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956211859_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09740692,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8374335,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"bounds":{"left":0.85272604,"top":0.019952115,"width":0.062832445,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"17","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00930851,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.006981383,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.7293883,"top":0.10055866,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.7390292,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.7463431,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","depth":4,"bounds":{"left":0.43051863,"top":0.09736632,"width":0.32280585,"height":0.90263367},"on_screen":true,"value":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-4729423357167171668
|
-8235799205988284024
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
81471
|
2826
|
27
|
2026-05-28T08:16:51.964608+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956211964_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.02111111},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"17","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.019444445,"height":0.02111111},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.025555555},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.014583333,"height":0.025555555},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","depth":4,"on_screen":true,"value":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-4729423357167171668
|
-8235799205988284024
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
81468
|
NULL
|
NULL
|
NULL
|
|
81472
|
2827
|
39
|
2026-05-28T08:16:57.995978+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956217995_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09740692,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8374335,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"bounds":{"left":0.85272604,"top":0.019952115,"width":0.062832445,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"17","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00930851,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.006981383,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.7293883,"top":0.10055866,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.7390292,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.7463431,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","depth":4,"bounds":{"left":0.43051863,"top":0.09736632,"width":0.32280585,"height":0.90263367},"on_screen":true,"value":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
4195952255238992687
|
-8812277550477751928
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}...
|
81470
|
NULL
|
NULL
|
NULL
|
|
81473
|
2826
|
28
|
2026-05-28T08:16:58.099313+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956218099_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.02111111},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"17","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.019444445,"height":0.02111111},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.025555555},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
2797364124384554827
|
-7623060321892881446
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
17
Previous Highlighted Error
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴2-zshscreenpipe"Digest:sha256:d6b7ebd9b71c0480b909d77fceada3df720c6594e4c853228765509b36f52db6Status: Imageis up todate for 438740370364.dkr.ecr.us-east-2.amazonaws.com/jiminny/app/q438740370364.dkr.ecr.us-east-2.amazonaws.com/jiminny/app/qa:arm64v8-latestWhat's next:View a summary of image vulnerabilities and recommendations → docker scoutquickviewlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20915-fix-missing-header-text-docker exec -it docker_lamp_1 ./vendor/bin/php-cs-fixer fix--config=.php-cs-fixer.dist.plPHP CS Fixer 3.95.1 Adalbertus by Fabien Potencier, Dariusz Ruminskiand contributors.PHP runtime: 8.5.5Loadedconfigdefault from ".php-cs-fixer.dist.php"Running analysis on 7cores with 10files per process.5698/5698100%1) app/Services/Mail/TextRelayService.php (statement_indentation)begin diff/home/jiminny/app/Services/Mail/TextRelayService.php+++/home/jiminny/app/Services/Mail/TextRelayService.php-67,7 +67,7 @eSjob = new EmailTextRelay(SmessageId, SrelayedText);Sjob-›onQueue(Constants: :QUEUE_EMAILS);dispatch($job);dispatch($job);Log: :info(' [TextRelayService]Successfully dispatched message', ["message_id'= SmessageId,end diffFixed 1 of 5698 files in 84.046 seconds, 701.18 MBmemory usedDetected deprecations in use (they will stop working in next major release)- Rule set"@PHP74Migration" is deprecated. Use"@PHP7x4Migration"instead.- Rule set "@PHP80Migration" is deprecated. Use "@PHP8x®Migration" instead.- Rule set "@PHP81Migration" is deprecated. Use "@PHP8x1Migration" instead.- Rule set "@PHP82Migration" is deprecated. Use "@PHP8x2Migration" instead.- Rule set "@PHP83Migration" is deprecated. Use "@PHP8x3Migration"instead.- Rule set "@PHP84Migration" is deprecated. Use "@PHP8x4Migration" instead.What's next:Try Docker Debug for seamless, persistent debugging tools in any containeror image »Learn more at https://docs.docker.com/go/debug-cli/lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20915-fix-missing-header-text-• •HomeDMsActivityFilesLater..•More+ED→Jiminny... vw Starrea& platform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday# jbu-team-info# jiminny-bg# platform-tickets# product_launches# random# releases# support# thank-yous# the_people_of_jimi...• Direct messages& Petko Kashinski% Galya Dimitrova&. Stefka Stoyanova: Todor StamatovStalivan Ganraiou100% <78 • Thu 28 May 11:16:57Describe what you are looking for* & platform-inner-team& 106 0• MessagesP Channel OverviewMore v+Yesterday ~Resolve rrir v.oiotPreview in SlackStatusBacklogPriority= MediumAssigneeUnassignedAs of yesterday at 6:20 PM RefreshOpen in Jira*+ SummarizeToday ~NewNikolay Nikolov 10:52 AMФикс за пускане на remote commands за staging:https://github.com/jiminny/app/pull/12132#12132 Fix stage profile for remote commandsrunJIRA: JY-XXXXDeployment notes:• NoneComments1V1jiminny/app| May 26th Added by GitHubMessage & platform-inner-team...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
81474
|
2827
|
40
|
2026-05-28T08:17:01.003763+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956221003_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09740692,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8374335,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"bounds":{"left":0.85272604,"top":0.019952115,"width":0.062832445,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.37632978,"top":0.10055866,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"15","depth":4,"bounds":{"left":0.3856383,"top":0.10055866,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.39694148,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.40425533,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.7293883,"top":0.10055866,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.7390292,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.7463431,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","depth":4,"bounds":{"left":0.43051863,"top":0.09736632,"width":0.32280585,"height":0.90263367},"on_screen":true,"value":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
1764831529811932805
|
-8307856800295171704
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
81475
|
2826
|
29
|
2026-05-28T08:17:29.184326+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956249184_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"15","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","depth":4,"on_screen":true,"value":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
1764831529811932805
|
-8307856800295171704
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
81473
|
NULL
|
NULL
|
NULL
|
|
81476
|
2827
|
41
|
2026-05-28T08:17:31.308113+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956251308_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09740692,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8374335,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"bounds":{"left":0.85272604,"top":0.019952115,"width":0.062832445,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.37632978,"top":0.10055866,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"15","depth":4,"bounds":{"left":0.3856383,"top":0.10055866,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.39694148,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.40425533,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.7293883,"top":0.10055866,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.7390292,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.7463431,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","depth":4,"bounds":{"left":0.43051863,"top":0.09736632,"width":0.32280585,"height":0.90263367},"on_screen":true,"value":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
1764831529811932805
|
-8307856800295171704
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
81474
|
NULL
|
NULL
|
NULL
|
|
81477
|
2826
|
30
|
2026-05-28T08:17:50.920103+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956270920_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"15","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","depth":4,"on_screen":true,"value":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-8341700080930998891
|
-8235816798443288184
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
81478
|
2827
|
42
|
2026-05-28T08:17:50.815333+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956270815_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
8043719072324535154
|
-8628527368849355612
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
PhpStorm$2 JY-20915-fix-m Project: faVsco.js, menu
PhpStorm$2 JY-20915-fix-miss©MailChannelService.phpMeetingGeneratorNotification#OAuth2PlaybooksRecallAlStrategyStreaminga TeamTelephonyaUserPilot#Webhook© AbstractService.php©ActivityProviderFactory.php©ActivityService.php©ApiResponseService.phpeeonaraneacarhes oool©InsightSeatService.php© InstantMeetingService.phpCootRunWindow© SyneMailbox.php© TextRelayServiceTest.phpE .env.production3: vane (unetton arereurentenv/romenteSnessage = $service-susers_nessages->get(Smailbox, Snessageld);Sheaders = Snessage->getPayLoad()->getHeaders():SoriginalTo = nutz:lSto = null;1f (Sheader->nameaas Xeol-urzethal-lo1 elseif (Sheader-»nane uns "To") €Sreciptent = SoriginalTo 2? Sto;Lf (Srecipient (== null) 4Smatches = $this->matchesExpectedRecipient(Srecipient, $expectedAlias, $expectedHost)'=© Jiminny.phpA SF giminny@localhost)[2826-05-28 87:47:50) Local. INFO: Sparans(startHistoryId) => 359021-correlatzon10:%aC0/1105-C2415-4442-17826-85-28 87:47:58 Local.wFu: SnessagchzscoryA console [PROD]# consoe leu.1d":*87f39623-3deb-4827-a8cf-b862acc93289**trace10: [CREDIT_CARD]-a8cт-0862aec93789-%17876-85528 87-S8857omuotfteSoamane[historyTypes] => nessageAddedstartHistorytoll50%2"ph67/306-7350-172h-6789-4017456066550 "tлaса 36".-62a0Rp6p-1669-hcR4-h1de-R/3ceccba6at*[2826-85-28 07:50:58] Local.INF0: SnessageHistory{"correlation_id":"ebf74306-735e-472b-b780-f9a7fS6e465S*,"trace_1d":*b2a98e4e-d669-4c04-b1de-843cecc6a601*}2924-05.28 87-55-17 1 1oc01 TNSh: Soanans[nistoryTypes) => nessageAdded(startHistoryId] => 359921-4d4a-b84b-a8531ca414a7*}(2826-05-28 87:SS:12] Local.INF0: SmessageHistory{"correlation_id":"25971837-31f1-431b-ad59-e898eb48b0Sf*, "trace_id*:"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7*}[2826-85-28 08:00:53] Local.INF0: Sparansmistorvivoes => messageadded[startHistoryid) => 359025connel atson o""naosynoo%ctheyerark -chn chcoaiieuooace aeuei aioowe ser.oSec-hsyiuhichthuOierhoR RRohieSaioetst SrassadelsromX6c82470-7042-4566.05cc-h52026Ac24h7"[2826-05-28 88:05:23] Local.INFO: SparansCascaderner hensemwietTO0У L78• Thu 28 May 11:17:50U TextRelayServiceTest~+0.What about this. Seems the + sign is in email. Wll ti still work and howYes, this will work correctly. Let me trace through the logic with this exact emaillo tncader valtos catchen2444700 SyxPorlheeeRoosueonnrcopheM soler onoirt8carchenttocho0LyaPors.cra8808.0o.wot.tdwrinw.conhos,chict:Xwoihnv.cosesX1419thh.os1/ 3. Strip plus tag fron local partstoca Base= exolodel"*,catch=a14447700.57706...e"carch-alt// 4. Compare alías: 'catch-all' ma= 'catch-all' 7 - returns truSo isforcurrentEnvi ronsentü returns tre and the messace docaeds to oe disoatchedThen in EnsilTextRelay job, parseRecipient() uses the To header directly and the regex \8+).1d+).(a-zA-20-- the & prefixbelore tne phoné numbers is stripped oy parsekeciotentintoentities wnich prepends + ilselt anyway.Everything works end-to-end. Now you just need to re-apply the to header falliback fix so these messagesice.0ho #1187-716Fix is back in place and the temporary headers oresent disgnostic logging is removed. The tests already retlcctthis logic from earlier. You're good to deploy.Ask anything (XOL)-@ eodtAdhotvKwoeunate186:32 UTF-8• C2 4 space:...
|
81474
|
NULL
|
NULL
|
NULL
|
|
81479
|
2827
|
43
|
2026-05-28T08:18:00.149862+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956280149_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09740692,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8374335,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"bounds":{"left":0.85272604,"top":0.019952115,"width":0.062832445,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.37632978,"top":0.10055866,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"15","depth":4,"bounds":{"left":0.3856383,"top":0.10055866,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.39694148,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.40425533,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.7293883,"top":0.10055866,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.7390292,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.7463431,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","depth":4,"bounds":{"left":0.43051863,"top":0.09736632,"width":0.32280585,"height":0.90263367},"on_screen":true,"value":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
1764831529811932805
|
-8307856800295171704
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
81480
|
2826
|
31
|
2026-05-28T08:18:00.251289+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956280251_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"15","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","depth":4,"on_screen":true,"value":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
1764831529811932805
|
-8307856800295171704
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
81477
|
NULL
|
NULL
|
NULL
|
|
81481
|
2826
|
32
|
2026-05-28T08:18:10.862620+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956290862_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER₴81DEV ( SlackFileEditViewGoHistoryWindowHelpDOCKER₴81DEV (docker)₴2-zshscreenpipe"Digest:sha256:d6b7ebd9b71c0480b909d77fceada3df720c6594e4c853228765509b36f52db6Status: Imageis up to date for 438740370364.dkr.ecr.us-east-2.amazonaws.com/jiminny/app/‹438740370364.dkr.ecr.us-east-2.amazonaws.com/jiminny/app/qa:arm64v8-latestWhat's next:View a summary ofimage vulnerabilities and recommendations docker scoutquickviewlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20915-fix-missing-header-text-docker exec -it docker_lamp_1 ./vendor/bin/php-cs-fixer fix--config=.php-cs-fixer.dist.plPHP CS Fixer 3.95.1 Adalbertus by Fabien Potencier, Dariusz Ruminskiand contributors.PHP runtime: 8.5.5Loadedconfigdefault from ".php-cs-fixer.dist.php"Running analysis on 7cores with 10files perprocess.5698/5698100%1) app/Services/Mail/TextRelayService.php (statement_indentation)begin diff/home/jiminny/app/Services/Mail/TextRelayService.php+++/home/jiminny/app/Services/Mail/TextRelayService.php-67,7 +67,7 @eSjob = new EmailTextRelay(SmessageId, SrelayedText);Sjob-›onQueue(Constants: :QUEUE_EMAILS);dispatch($job);dispatch($job);Log: :info(' [TextRelayService]Successfully dispatched message', ["message_id'= SmessageId,end diffFixed 1 of 5698 files in 84.046 seconds, 701.18 MBmemory usedDetected deprecations in use (they will stop working in next major release)- Rule set"@PHP74Migration" is deprecated. Use"@PHP7x4Migration"instead.- Rule set "@PHP80Migration" is deprecated. Use "@PHP8x®Migration" instead.- Rule set "@PHP81Migration" is deprecated. Use "@PHP8x1Migration" instead.- Rule set "@PHP82Migration" is deprecated. Use "@PHP8x2Migration" instead.- Rule set "@PHP83Migration" is deprecated. Use "@PHP8x3Migration"instead.- Rule set "@PHP84Migration" is deprecated. Use "@PHP8x4Migration" instead.What's next:Try Docker Debug for seamless, persistent debugging tools in any containeror image »Learn more at https://docs.docker.com/go/debug-cli/lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20915-fix-missing-header-text-• •HomeDMsActivityFilesLater..•More+ED→Jiminny... vw Starrea& platform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday# jbu-team-info# jiminny-bg# platform-tickets# product_launches# random# releases# support# thank-yous# the_people_of_jimi...• Direct messages& Petko Kashinski% Galya Dimitrova&. Stefka Stoyanova: Todor StamatovStalivan Ganraiou100% <78• Thu 28 May 11:18:10Describe what you are looking for* & platform-inner-team& 106 0• MessagesP Channel OverviewMore v+Yesterday ~Resolve rrir v.oiotPreview in SlackStatusBacklogPriority= MediumAssigneeUnassignedAs of yesterday at 6:20 PM RefreshOpen in Jira*+ SummarizeToday ~NewNikolay Nikolov 10:52 AMФикс за пускане на remote commands за staging:https://github.com/jiminny/app/pull/12132#12132 Fix stage profile for remote commandsrunJIRA: JY-XXXXDeployment notes:• NoneComments1V1jiminny/app| May 26th Added by GitHubMessage & platform-inner-team...
|
NULL
|
8939761280494406748
|
NULL
|
click
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER₴81DEV ( SlackFileEditViewGoHistoryWindowHelpDOCKER₴81DEV (docker)₴2-zshscreenpipe"Digest:sha256:d6b7ebd9b71c0480b909d77fceada3df720c6594e4c853228765509b36f52db6Status: Imageis up to date for 438740370364.dkr.ecr.us-east-2.amazonaws.com/jiminny/app/‹438740370364.dkr.ecr.us-east-2.amazonaws.com/jiminny/app/qa:arm64v8-latestWhat's next:View a summary ofimage vulnerabilities and recommendations docker scoutquickviewlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20915-fix-missing-header-text-docker exec -it docker_lamp_1 ./vendor/bin/php-cs-fixer fix--config=.php-cs-fixer.dist.plPHP CS Fixer 3.95.1 Adalbertus by Fabien Potencier, Dariusz Ruminskiand contributors.PHP runtime: 8.5.5Loadedconfigdefault from ".php-cs-fixer.dist.php"Running analysis on 7cores with 10files perprocess.5698/5698100%1) app/Services/Mail/TextRelayService.php (statement_indentation)begin diff/home/jiminny/app/Services/Mail/TextRelayService.php+++/home/jiminny/app/Services/Mail/TextRelayService.php-67,7 +67,7 @eSjob = new EmailTextRelay(SmessageId, SrelayedText);Sjob-›onQueue(Constants: :QUEUE_EMAILS);dispatch($job);dispatch($job);Log: :info(' [TextRelayService]Successfully dispatched message', ["message_id'= SmessageId,end diffFixed 1 of 5698 files in 84.046 seconds, 701.18 MBmemory usedDetected deprecations in use (they will stop working in next major release)- Rule set"@PHP74Migration" is deprecated. Use"@PHP7x4Migration"instead.- Rule set "@PHP80Migration" is deprecated. Use "@PHP8x®Migration" instead.- Rule set "@PHP81Migration" is deprecated. Use "@PHP8x1Migration" instead.- Rule set "@PHP82Migration" is deprecated. Use "@PHP8x2Migration" instead.- Rule set "@PHP83Migration" is deprecated. Use "@PHP8x3Migration"instead.- Rule set "@PHP84Migration" is deprecated. Use "@PHP8x4Migration" instead.What's next:Try Docker Debug for seamless, persistent debugging tools in any containeror image »Learn more at https://docs.docker.com/go/debug-cli/lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20915-fix-missing-header-text-• •HomeDMsActivityFilesLater..•More+ED→Jiminny... vw Starrea& platform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday# jbu-team-info# jiminny-bg# platform-tickets# product_launches# random# releases# support# thank-yous# the_people_of_jimi...• Direct messages& Petko Kashinski% Galya Dimitrova&. Stefka Stoyanova: Todor StamatovStalivan Ganraiou100% <78• Thu 28 May 11:18:10Describe what you are looking for* & platform-inner-team& 106 0• MessagesP Channel OverviewMore v+Yesterday ~Resolve rrir v.oiotPreview in SlackStatusBacklogPriority= MediumAssigneeUnassignedAs of yesterday at 6:20 PM RefreshOpen in Jira*+ SummarizeToday ~NewNikolay Nikolov 10:52 AMФикс за пускане на remote commands за staging:https://github.com/jiminny/app/pull/12132#12132 Fix stage profile for remote commandsrunJIRA: JY-XXXXDeployment notes:• NoneComments1V1jiminny/app| May 26th Added by GitHubMessage & platform-inner-team...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
81482
|
2827
|
44
|
2026-05-28T08:18:10.964729+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956290964_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
8043719072324535154
|
-8628527368849355612
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
PhpStormEV faVsco,ls ~Vie Project: faVsco.js, menu
PhpStormEV faVsco,ls ~View$2 JY-20915-fix-missCootRunWindow©InternetMessagelnterface.phy©MailChannelService.phpo Textrelkysewice. oneMeetingGeneratorNotification#OAuth2PlaybooksRecallAl© TextRelayServiceTest.phpStrategyStreaminga TeamTelephonyaUserPilot#Webhook© AbstractService.php©ActivityProviderFactory.php©ActivityService.php© ApiResponseService.phpeeonaraneacarhes oool©InsightSeatService.php© InstantMeetingService.php@ IntercomService.phpE env.productiona, funten rercrenter/remeteSnessage = $service-susers_nessages->get(Smailbox, Snessageld);Sheaders = Snessage->getPayLoad()->getHeaders():SoriginalTo = nutl;Sto = null;1f (Sheader->name• a= "X-6m-Original-To') (} elseif (Sheader->nane uue "To') €Sreciptent = SoriginalTo 2? Sto;1f (Srecipient [== null) 4Smatches = $this->matchesExpectedRecipient(Srecipient, $expectedAlias, $expectedHost)=© Jiminny.phpA SF giminny@localhost][2826-05-28 87:47:50) Local. INFO: Sparans(startHistoryId) => 359021-correlatzon10:%aC0/1105-C2415-4442-17826-85-28 87:47:58 Local.wFu: SnessagchzscoryA console [PROD]# consoe leu.1d":*87f39623-3deb-4827-a8cf-b862acc93289**trace10: [CREDIT_CARD]-a8cт-0862aec93789-17876-85528 87-S8857omuotfteSoamane[historyTypes] => nessageAddedstartHistorytoll50%2"ph67/306-7350-172h-6789-4017456066550 "tлaса 36".-62a0Rp6p-1669-hcR4-h1de-R/3ceccba6at*[2826-85-28 07:50:58] Local.INF0: SnessageHistory{"correlation_id":"ebf74306-735e-472b-D780-f9a7f56e465S*, "trace_1d*:*b2a98e4e-d669-4c04-b1de-843ceçc6a601*}2924-05-28 07-55-17 1 1oc01 THSn• Snanane[nistoryTypes) => nessageAdded(startHistoryId] => 359921-4d4a-b84b-a8531ca414a7*}(2826-05-28 87:SS:12] Local.INF0: SmessageHistory{"correlation_id":"25971837-31f1-431b-ad59-e898eb48b0Sf*, "trace_id*:"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7*}[2826-85-28 08:00:53] Local.INF0: Sparansmistorvnvoes > messageadded[startHistoryid) => 359025connel atson o""naosynoo%ctheyerark -chn chcoaiieuooace aeuei aioowe ser.oSec-hsyiuhichthuierhooR neohieSa oetet shacsadel stomX6c82479-7042-1566.05cc-h529269c24h7m[2826-85-28 88:05:23] Local.INFO: Sparans7o0sLXoo Inu co moy ti-lo.lU TextRelayServiceTest~Cascaderner hensemwiet+0.What about this. Seems the + sign is in email. Wil ti still work and howYes, this will work correctly. Let me trace through the logic with this exact emailo tncader valtos catchen2444700 SyxPorlheeeRoosueonnrcopheM soler onoirt8carchenttocho0LyaPors.cra8808.0o.wot.tdwrinw.conthos,chict:Xwloihy.cos=ssXr9th.os1/ 3. Strip plus tag fron local partstoca Basc= exolodel",catch=a14447700157786...Ol"carch-alt// 4. Compare alías: 'catch-all' ma= 'catch-all' 7 - returns truThen in EnsilTextRelay job, parseRecipient() uses the To header directly and the regex \d+).1d+). [a-zA-20-- the * prefixbelore tne phoné numbers is stripped oy parsekeciotentintoentities wnich prepends + ilselt anyway.Everything works end-to-end. Now you just need to re-apply the to header falliback fix so these messagesice.0ho #l187-718Fix is back in place and the temporary headers oresent disgnostic logging is removed. The tests already retlcctthis logic from earlier. You're good to deploy.Ask anything (XOL)-@ eodtAdhotvKtwodeurlete186:32 UTF-8• C2 4 space:...
|
81479
|
NULL
|
NULL
|
NULL
|
|
81483
|
2826
|
33
|
2026-05-28T08:18:13.551111+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956293551_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"15","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-987438372797753690
|
-6438878488507806805
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification...
|
81481
|
NULL
|
NULL
|
NULL
|
|
81484
|
2827
|
45
|
2026-05-28T08:18:13.655213+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956293655_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09740692,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8374335,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"bounds":{"left":0.85272604,"top":0.019952115,"width":0.062832445,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.37632978,"top":0.10055866,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"15","depth":4,"bounds":{"left":0.3856383,"top":0.10055866,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.39694148,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.40425533,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.7293883,"top":0.10055866,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.7390292,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.7463431,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","depth":4,"bounds":{"left":0.43051863,"top":0.09736632,"width":0.32280585,"height":0.90263367},"on_screen":true,"value":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
1764831529811932805
|
-8307856800295171704
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
81485
|
2826
|
34
|
2026-05-28T08:18:16.818706+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779956296818_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"15","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","depth":4,"on_screen":true,"value":"[2026-05-28 07:47:50] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:47:50] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"9acc7103-e275-4442-a80e-72ca0233ad9d\",\"trace_id\":\"87f39623-3deb-4827-a0cf-b862aec93209\"}\n[2026-05-28 07:50:57] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:50:58] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"ebf74306-735e-472b-b780-f9a7f56e4655\",\"trace_id\":\"b2a98e4e-d669-4c04-b1de-043cecc6a601\"}\n[2026-05-28 07:55:17] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359021\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 07:55:17] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"25971837-31f1-431b-ad59-e890eb40b05f\",\"trace_id\":\"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7\"}\n[2026-05-28 08:00:53] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:00:54] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"da957797-f328-4bf7-8a33-961c0cca120c\",\"trace_id\":\"34c82f30-39f2-45cf-95cc-b520260c2fb3\"}\n[2026-05-28 08:05:23] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:05:24] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"c5339dcc-46c1-45a4-81f9-ede0203ab266\",\"trace_id\":\"627196cf-0a09-465a-ab3e-10e546adfcde\"}\n[2026-05-28 08:10:44] local.INFO: $params \nArray\n(\n [historyTypes] => messageAdded\n [startHistoryId] => 359025\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}\n[2026-05-28 08:10:44] local.INFO: $messageHistory \nArray\n(\n)\n {\"correlation_id\":\"8667713e-79c8-46a6-b5a4-b13351d287da\",\"trace_id\":\"52ec740a-b685-4b96-abda-8e5ab1057ea6\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
1764831529811932805
|
-8307856800295171704
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 07:47:50] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:47:50] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"9acc7103-e275-4442-a80e-72ca0233ad9d","trace_id":"87f39623-3deb-4827-a0cf-b862aec93209"}
[2026-05-28 07:50:57] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:50:58] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"ebf74306-735e-472b-b780-f9a7f56e4655","trace_id":"b2a98e4e-d669-4c04-b1de-043cecc6a601"}
[2026-05-28 07:55:17] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359021
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 07:55:17] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"25971837-31f1-431b-ad59-e890eb40b05f","trace_id":"c3f63c2c-d21b-4d4a-b84b-a8531ca414a7"}
[2026-05-28 08:00:53] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:00:54] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"da957797-f328-4bf7-8a33-961c0cca120c","trace_id":"34c82f30-39f2-45cf-95cc-b520260c2fb3"}
[2026-05-28 08:05:23] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:05:24] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"c5339dcc-46c1-45a4-81f9-ede0203ab266","trace_id":"627196cf-0a09-465a-ab3e-10e546adfcde"}
[2026-05-28 08:10:44] local.INFO: $params
Array
(
[historyTypes] => messageAdded
[startHistoryId] => 359025
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
[2026-05-28 08:10:44] local.INFO: $messageHistory
Array
(
)
{"correlation_id":"8667713e-79c8-46a6-b5a4-b13351d287da","trace_id":"52ec740a-b685-4b96-abda-8e5ab1057ea6"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
81597
|
2832
|
14
|
2026-05-28T08:31:24.150359+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779957084150_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Code changed:
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"15","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-8171751502949769767
|
-5862347367460205653
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Code changed:
Hide...
|
81596
|
NULL
|
NULL
|
NULL
|
|
81599
|
2833
|
15
|
2026-05-28T08:31:25.793080+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779957085793_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09740692,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8374335,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"bounds":{"left":0.85272604,"top":0.019952115,"width":0.062832445,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.37632978,"top":0.10055866,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"15","depth":4,"bounds":{"left":0.3856383,"top":0.10055866,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.39694148,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.40425533,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":4,"bounds":{"left":0.43051863,"top":0.09736632,"width":0.32280585,"height":0.40223464},"on_screen":true,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-2129860785133473404
|
-4704983834769847381
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
81600
|
2832
|
15
|
2026-05-28T08:31:43.909932+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779957103909_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-4528724110787610736
|
2604719229101344208
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
iTerm2ShellEditViewSessionScriptsProfilesWindowHelp‹$0A-zshscreenpipe"DOCKERO ₴1DEV (docker)worker-calendar:worker-calendar_00:startedworker-conferences:worker-conferences_00: startedworker-crm-sync:worker-crm-sync_00: startedworker-crm-update:worker-crm-update_00: startedworker-download:worker-download_00:startedworker-emails:worker-emails_00:startedworker-es-update:worker-es-update_00:startedworker-nudges:worker-nudges_00: started₴2-zshО 84-zshWhat's next:Try Docker Debug forLearnseamless, persistentdebugging tools in any container or image → docker debug docker_lamp_1moreat [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20915-fix-missing-header-text-relay) $csfixdocker exec -it docker_lamp_1•/vendor/bin/php-cs-fixer fix--config=.php-cs-fixer.dist.php-v--using-cache=no --diffPHP CS Fixer 3.95.1 Adalbertus by Fabien Potencier, Dariusz Ruminski and contributors.PHP runtime: 8.5.5Loaded config default from ".php-cs-fixer.dist.php".Running analysis on 7 cores with 10 files per process.5698/5698 C80100%*5ec2-user@ip-10-30-1...O 86100% <78 • Thu 28 May 11:31:43T81ec2-user@ip-10-30-140-...$7Fixed 0 of 5698 files in 52.731 seconds, 799.06 MB memory usedDetected deprecations in use (they will stop working in next major release):- Rule set"@PHP74Migration" is deprecated. Use"@PHP7x4Migration" instead.- Rule set "@PHP80Migration" is deprecated. Use "@PHP8x®Migration" instead.- Rule set "@PHP81Migration" is deprecated. Use "@PHP8x1Migration" instead.- Rule set "@PHP82Migration" is deprecated. Use "@PHP8x2Migration" instead.- Rule set "@PHP83Migration" is deprecated. Use "@PHP8x3Migration"instead.- Rule set "@PHP84Migration" is deprecated. Use "@PHP8x4Migration" instead.What's next:Try Docker Debug for seamless, persistent debugging tools in any container or image + docker debug docker_lamp_1Learn more at https://docs.docker.com/go/debug-cli/lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20915-fix-missing-header-text-relay) $D...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
81601
|
2833
|
16
|
2026-05-28T08:31:44.488823+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779957104488_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhpStormFV faVsco.|s ~ProjectvViewNeweNNC$2 JY-209 PhpStormFV faVsco.|s ~ProjectvViewNeweNNC$2 JY-20915-fix-missioCoocKetucioTOOI-Window) Kernel.php© SyneMailbox.php©InternetMessagelnterface.phg© TextRelayServiceTest.phpfyminny.oheE env.production© MailChannelService.phpclass TextReLayServiceo Textrelkysewice.onoavare tuncczon csroncurehcchvarohaehtMeetingGeneratoranoucadorEOHUNPlaybooks—KeCaLA& Dockerfie1 catch (\Exception $e) (Log: :error ((message:)" [TextRelayService) Failed to inspect message', t'nessage_id' => Snessageid,'exception' => Se-›getMessageO).Jotaeo(Sentry::captureException(Se):a Team#UserPilotWebhookC AbstractSemvice cno©ActivityProviderFactory.phpCActviysemce cno©ApiResponseService.phpeeonaraneacarhes ood©InsightSeatService.php© InstantMeetingService.php© IntercomService.php©lpapiClient.phpirávate function natchesExpectedRecipfent (string Srecipient, string SexpoctedAlias, string SexpectedHoDoants - exorodelseif (count(Sparts) la= 2 ll strcasecno(Spartsii]. SexpectedHost) (a= 0)%return false.Changes o luesF .env.local app© JiminnyDebugCommand.php app/Console/Commandsme logging.php config@ PlaybackService.pho app/Services© TextRelayService.php app/Services/Mailoex RehyswMicalieaoho› Unversioned Files 9 filesE laravellog X 4 SF jiminny@localhost)HSJocal ([iminny@localhost)A console (PROD)A console [STAGING)A console (EU]TO0У L7oo tnu comoy tiroteeU TextRelayServiceTest~+0 .fox@TextRelayServiceTest-phprner hensewietResdTextRelayScrvicalest.oho #L154-188eexKeayeMicesthontRead TextRelayServiceTest.php #L150-199Sasrched testistorcurrent Environment.allsBackio ohesder in testerUnSamrices Moiln extRelay Service est.oho.I need to check if there's a duplicate test now. Let me search for all test methods in the file:ResonexRehyscwicelcscono 00-2lD TextRelayServiceTest.phpAsk amahioo+ < Code SWE-1.6+1-10003ditterences+ → , Side-by-side viewerDo notignorey Highlight words71 • ?8828865601Sthiisoassent sailse Sresultpublic function testIsForCurrentEnvironnentIgnoresToHeader(): voidConfig::set('jininny-google_text_host', 'txt.jiminny.com');Snessage = Sthis-›createMock(GnailMessage: :class);Sresult = Snethod-›invoke(Sservice, SgnailService, 'catch-all', 'asg123', 'catch-all', 'txt.jiminny.com'):Sthis->assertFalse(Sresult);nublic functzion testlefondunnentEnwironnentWithEnotvHeadeneOe voi.nethodosserrccesgtolet ruePurtent vereionSthisosassentFalselSresultpublic function testIsForCurrentEnvironmentFallsBackToToHeader(): voidConfig::set("jininny.google text host'*txt.jininny.com');Smessage = Sthis-›createMock(GmailMessage::class):Smethod->setAccessibte(true);Sresult = Snethod->invoke(Sservice, SgnailService, 'catch-all', 'nsg123', 'catch-all', 'txt.jininny.con'):Scnis->asserclruelSresutooublie funatzion testleforCurcentEnvirdoc h0d->eeeeherueTAGEnactArem ditee sooutwnderAmereyenhensno....
|
NULL
|
6710810205627921530
|
NULL
|
visual_change
|
ocr
|
NULL
|
PhpStormFV faVsco.|s ~ProjectvViewNeweNNC$2 JY-209 PhpStormFV faVsco.|s ~ProjectvViewNeweNNC$2 JY-20915-fix-missioCoocKetucioTOOI-Window) Kernel.php© SyneMailbox.php©InternetMessagelnterface.phg© TextRelayServiceTest.phpfyminny.oheE env.production© MailChannelService.phpclass TextReLayServiceo Textrelkysewice.onoavare tuncczon csroncurehcchvarohaehtMeetingGeneratoranoucadorEOHUNPlaybooks—KeCaLA& Dockerfie1 catch (\Exception $e) (Log: :error ((message:)" [TextRelayService) Failed to inspect message', t'nessage_id' => Snessageid,'exception' => Se-›getMessageO).Jotaeo(Sentry::captureException(Se):a Team#UserPilotWebhookC AbstractSemvice cno©ActivityProviderFactory.phpCActviysemce cno©ApiResponseService.phpeeonaraneacarhes ood©InsightSeatService.php© InstantMeetingService.php© IntercomService.php©lpapiClient.phpirávate function natchesExpectedRecipfent (string Srecipient, string SexpoctedAlias, string SexpectedHoDoants - exorodelseif (count(Sparts) la= 2 ll strcasecno(Spartsii]. SexpectedHost) (a= 0)%return false.Changes o luesF .env.local app© JiminnyDebugCommand.php app/Console/Commandsme logging.php config@ PlaybackService.pho app/Services© TextRelayService.php app/Services/Mailoex RehyswMicalieaoho› Unversioned Files 9 filesE laravellog X 4 SF jiminny@localhost)HSJocal ([iminny@localhost)A console (PROD)A console [STAGING)A console (EU]TO0У L7oo tnu comoy tiroteeU TextRelayServiceTest~+0 .fox@TextRelayServiceTest-phprner hensewietResdTextRelayScrvicalest.oho #L154-188eexKeayeMicesthontRead TextRelayServiceTest.php #L150-199Sasrched testistorcurrent Environment.allsBackio ohesder in testerUnSamrices Moiln extRelay Service est.oho.I need to check if there's a duplicate test now. Let me search for all test methods in the file:ResonexRehyscwicelcscono 00-2lD TextRelayServiceTest.phpAsk amahioo+ < Code SWE-1.6+1-10003ditterences+ → , Side-by-side viewerDo notignorey Highlight words71 • ?8828865601Sthiisoassent sailse Sresultpublic function testIsForCurrentEnvironnentIgnoresToHeader(): voidConfig::set('jininny-google_text_host', 'txt.jiminny.com');Snessage = Sthis-›createMock(GnailMessage: :class);Sresult = Snethod-›invoke(Sservice, SgnailService, 'catch-all', 'asg123', 'catch-all', 'txt.jiminny.com'):Sthis->assertFalse(Sresult);nublic functzion testlefondunnentEnwironnentWithEnotvHeadeneOe voi.nethodosserrccesgtolet ruePurtent vereionSthisosassentFalselSresultpublic function testIsForCurrentEnvironmentFallsBackToToHeader(): voidConfig::set("jininny.google text host'*txt.jininny.com');Smessage = Sthis-›createMock(GmailMessage::class):Smethod->setAccessibte(true);Sresult = Snethod->invoke(Sservice, SgnailService, 'catch-all', 'nsg123', 'catch-all', 'txt.jininny.con'):Scnis->asserclruelSresutooublie funatzion testleforCurcentEnvirdoc h0d->eeeeherueTAGEnactArem ditee sooutwnderAmereyenhensno....
|
81599
|
NULL
|
NULL
|
NULL
|
|
81602
|
2832
|
16
|
2026-05-28T08:31:45.911289+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779957105911_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Code changed:
Hide
Sync Changes
Hide This Notification...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"15","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":4,"on_screen":true,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-2628780741070192589
|
-5857843767832835157
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Code changed:
Hide
Sync Changes
Hide This Notification...
|
81600
|
NULL
|
NULL
|
NULL
|
|
81603
|
2833
|
17
|
2026-05-28T08:31:47.546303+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779957107546_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09740692,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8374335,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"bounds":{"left":0.85272604,"top":0.019952115,"width":0.062832445,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.37632978,"top":0.10055866,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"15","depth":4,"bounds":{"left":0.3856383,"top":0.10055866,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.39694148,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.40425533,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":4,"bounds":{"left":0.43051863,"top":0.09736632,"width":0.32280585,"height":0.40223464},"on_screen":true,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-2129860785133473404
|
-4704983834769847381
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
81604
|
2832
|
17
|
2026-05-28T08:32:10.997533+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779957130997_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"15","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":4,"on_screen":true,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-2129860785133473404
|
-4704983834769847381
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
81605
|
2832
|
18
|
2026-05-28T08:32:13.729686+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779957133729_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
Editor for laravel.log...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"15","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"Editor for laravel.log","depth":4,"role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-3638810784233747753
|
-6006532924280239189
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
Editor for laravel.log...
|
81604
|
NULL
|
NULL
|
NULL
|
|
81613
|
2833
|
22
|
2026-05-28T08:32:31.877817+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779957151877_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Committing…
Project: faVsco.js, menu
JY-20915-fix- Committing…
Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
[2026-05-28 08:28:04] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"meeting-bot:schedule-bot","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"73199e23-a066-42ba-b189-2802e0869a44","trace_id":"e53672c2-0f50-409d-af25-84ab485c505d"}
[2026-05-28 08:28:04] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {"count":0} {"correlation_id":"73199e23-a066-42ba-b189-2802e0869a44","trace_id":"e53672c2-0f50-409d-af25-84ab485c505d"}
[2026-05-28 08:28:04] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"meeting-bot:schedule-bot","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"73199e23-a066-42ba-b189-2802e0869a44","trace_id":"e53672c2-0f50-409d-af25-84ab485c505d"}
[2026-05-28 08:28:06] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"dialers:monitor-activities","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"741b2c4e-6a44-4c46-b9fb-fce017aef225","trace_id":"804dc547-eb25-4b32-8d0f-c87019773085"}
[2026-05-28 08:28:06] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"dialers:monitor-activities","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"741b2c4e-6a44-4c46-b9fb-fce017aef225","trace_id":"804dc547-eb25-4b32-8d0f-c87019773085"}
[2026-05-28 08:28:09] local.NOTICE: Monitoring start {"correlation_id":"8ae5c131-edd9-463d-8161-875f4d34320f","trace_id":"1b6420c8-ef4e-4566-81b2-688696064648"}
[2026-05-28 08:28:09] local.NOTICE: Monitoring end {"correlation_id":"8ae5c131-edd9-463d-8161-875f4d34320f","trace_id":"1b6420c8-ef4e-4566-81b2-688696064648"}
[2026-05-28 08:28:10] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"mailbox:skip-lists:refresh","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"6f5390d3-abe7-4e56-a662-aeed1098941b","trace_id":"b57dc2df-2f4d-4d3b-b09a-aa6e61205d5e"}
[2026-05-28 08:28:10] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"mailbox:skip-lists:refresh","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"6f5390d3-abe7-4e56-a662-aeed1098941b","trace_id":"b57dc2df-2f4d-4d3b-b09a-aa6e61205d5e"}
[2026-05-28 08:28:12] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"mailbox:batch:process","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"ba694158-ea28-4ac1-b134-83ac485146e0","trace_id":"83a26b74-baa5-407e-9fc2-2b49d65b1c77"}
[2026-05-28 08:28:12] local.INFO: [EmailSchedule] STARTING batch process {"host":"docker_lamp_1"} {"correlation_id":"ba694158-ea28-4ac1-b134-83ac485146e0","trace_id":"83a26b74-baa5-407e-9fc2-2b49d65b1c77"}
[2026-05-28 08:28:12] local.INFO: [EmailSchedule] FINISHED batch process {"host":"docker_lamp_1","processed":0} {"correlation_id":"ba694158-ea28-4ac1-b134-83ac485146e0","trace_id":"83a26b74-baa5-407e-9fc2-2b49d65b1c77"}
[2026-05-28 08:28:12] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"mailbox:batch:process","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"ba694158-ea28-4ac1-b134-83ac485146e0","trace_id":"83a26b74-baa5-407e-9fc2-2b49d65b1c77"}
[2026-05-28 08:28:14] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"conference:monitor:count","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"b79833c7-3eab-4eb7-98bb-42359039b8fb","trace_id":"a8e159bc-867d-40af-bf7d-1228cf6d4f16"}
[2026-05-28 08:28:14] local.INFO: Running conference:monitor:count command for activities in (2026-05-28 08:26:00, 2026-05-28 08:28:00] {"correlation_id":"b79833c7-3eab-4eb7-98bb-42359039b8fb","trace_id":"a8e159bc-867d-40af-bf7d-1228cf6d4f16"}
[2026-05-28 08:28:14] local.INFO: [conference:monitor:count] No activities found in (2026-05-28 08:26:00, 2026-05-28 08:28:00] {"correlation_id":"b79833c7-3eab-4eb7-98bb-42359039b8fb","trace_id":"a8e159bc-867d-40af-bf7d-1228cf6d4f16"}
[2026-05-28 08:28:14] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"conference:monitor:count","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"b79833c7-3eab-4eb7-98bb-42359039b8fb","trace_id":"a8e159bc-867d-40af-bf7d-1228cf6d4f16"}
[2026-05-28 08:28:16] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"mailbox:batch:retry-failed","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"d51071d5-ead0-45f0-a07e-e3234074f884","trace_id":"77173d9f-596f-405f-ae55-ba117b66455d"}
[2026-05-28 08:28:16] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"calendar:sync","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.NOTICE: Calendar sync start {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"mailbox:batch:retry-failed","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"d51071d5-ead0-45f0-a07e-e3234074f884","trace_id":"77173d9f-596f-405f-ae55-ba117b66455d"}
[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1393,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1393,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1393,"provider":"google","refreshToken":"5aa7e2d96b53201cd16fca5d2e4ef3ad03320971fc064781d18aee3ae7b99fbf","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1393,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Account has been deleted"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1393,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1387,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1387,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1387,"provider":"google","refreshToken":"8157ac6de94842937194009e9c50e459253600f799dacf6a40755ffdbeb5bba6","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1387,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Account has been deleted"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1387,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1348,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1348,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1348,"provider":"google","refreshToken":"9e7d13d3032d0cb1b79d8e95aef01383e8e91eb52ff8ee960c8a0b6b95cd8c73","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1348,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1348,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1361,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1361,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1361,"provider":"google","refreshToken":"6c843da199c2b9907445329304fcc4ec5057a4ee748d8299641764395c08e1fd","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1361,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Account has been deleted"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1361,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1310,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1310,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1310,"provider":"google","refreshToken":"e34818922c2830a660813a63f6169a4a9a992ae2cccd7dc8dd7796cfdb470ef1","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1310,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1310,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1333,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1333,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1333,"provider":"google","refreshToken":"6c902986546d8e8da1dc539b046cdc1d458f519acc972e5b5f1d6a1a295165e0","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1333,"provider":"google","responseBody":{"error":"unauthorized_client","error_description":"Unauthorized"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1333,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1368,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1368,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1368,"provider":"google","refreshToken":"d2f128898ff8543bd16b69cfae37896ab85119b0f5ed2b431d739593bb600333","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1368,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1368,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1365,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1365,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1365,"provider":"google","refreshToken":"7676e4a9afcd082b413248ab5ec6e487021fec6a9bdf315860a59cefad9caad8","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1365,"provider":"google","responseBody":{"error":"unauthorized_client","error_description":"Unauthorized"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1365,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1364,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1364,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1364,"provider":"google","refreshToken":"dd5882ebce76e645292ce33ae74238abbb77c0a4ecc6a2bfe723cad82e72ba8e","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1364,"provider":"google","responseBody":{"error":"unauthorized_client","error_description":"Unauthorized"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1364,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1370,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1370,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1370,"provider":"office","refreshToken":"b7ee8035306d0043cea6e00e7c4fe14f745e44074a1194db62a31cdf8b70af3e","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1370,"provider":"office","responseBody":"{\"error\":\"invalid_client\",\"error_description\":\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 41d8db5c-a91f-41a6-9b5c-22a6c99b9100 Correlation ID: 70bc0a6f-1565-4e74-94dc-419d94108fa9 Timestamp: 2026-05-28 08:28:18Z\",\"error_codes\":[7000215],\"timestamp\":\"2026-05-28 08:28:18Z\",\"trace_id\":\"41d8db5c-a91f-41a6-9b5c-22a6c99b9100\",\"correlation_id\":\"70bc0a6f-1565-4e74-94dc-419d94108fa9\",\"error_uri\":\"https://login.microsoftonline.com/error?code=7000215\"}"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1370,"provider":"office","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1202,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1202,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1202,"provider":"office","refreshToken":"b458799ccc29b21a6e2eb5260fdb63e49ccba21bf942a3973fb63799bd7f0afe","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1202,"provider":"office","responseBody":"{\"error\":\"invalid_client\",\"error_description\":\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: d3d14dfc-1b70-40c4-b9db-fab12f748300 Correlation ID: 4c5f746c-8366-44c1-8733-6877607826db Timestamp: 2026-05-28 08:28:19Z\",\"error_codes\":[7000215],\"timestamp\":\"2026-05-28 08:28:19Z\",\"trace_id\":\"d3d14dfc-1b70-40c4-b9db-fab12f748300\",\"correlation_id\":\"4c5f746c-8366-44c1-8733-6877607826db\",\"error_uri\":\"https://login.microsoftonline.com/error?code=7000215\"}"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1202,"provider":"office","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1502,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1502,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: Calendar sync job dispatched {"calendar_id":501} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1300,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1300,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1300,"provider":"google","refreshToken":"4b811db0725fd9602a95943519a7da935e2a5065da7d9ebfcb170752e3e1ddb8","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1300,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Account has been deleted"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1300,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1409,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1409,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1409,"provider":"google","refreshToken":"e2a3f2d06894894eed1ee87d9db1ace77d4d42ee6e1288a8940ad2c10333b0c4","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1409,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1409,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1352,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1352,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1352,"provider":"google","refreshToken":"dd4b16b00fdc1216da6b717c02338c073636e29162826b2de6db3f064fc029eb","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1352,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1352,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1296,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1296,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1296,"provider":"office","refreshToken":"011ae723c9d800c674e0b4be76f49fc046dac7d501b66c59ef0d9549cfa56ae5","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1502,"provider":"google"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1502,"provider":"google"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [Calendar] Processing sync {"calendarId":"a33076c1-8d97-431a-99f0-85c9524e118b","from":null,"to":null,"delta":"CIiFh8TP44kDEIiFh8TP44kDGAUgkZvkzgIokZvkzgI=","last_sync":"2024-12-09 07:12:53","dateMode":"daily"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"integration-app","crm_owner":1695,"team_id":3143} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1502,"provider":"google"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1502,"provider":"google"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1296,"provider":"office","responseBody":"{\"error\":\"invalid_client\",\"error_description\":\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: dd83a147-95bc-407c-8c9b-3c14e7cb7d00 Correlation ID: bb16bae3-b3c4-467e-bd95-4e7ab85364c9 Timestamp: 2026-05-28 08:28:20Z\",\"error_codes\":[7000215],\"timestamp\":\"2026-05-28 08:28:20Z\",\"trace_id\":\"dd83a147-95bc-407c-8c9b-3c14e7cb7d00\",\"correlation_id\":\"bb16bae3-b3c4-467e-bd95-4e7ab85364c9\",\"error_uri\":\"https://login.microsoftonline.com/error?code=7000215\"}"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1296,"provider":"office","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":391,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":391,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":391,"provider":"office","refreshToken":"00045eebae0f39b34887c6d53f92ae78064f7145e1f4b67754aebd03cfb2d881","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [Google Calendar] Failed to watch channel for calendar {"calendarId":"a33076c1-8d97-431a-99f0-85c9524e118b","code":400,"reason":"{
\"error\": {
\"errors\": [
{
\"domain\": \"global\",
\"reason\": \"push.webhookUrlNotHttps\",
\"message\": \"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\"
}
],
\"code\": 400,
\"message\": \"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\"
}
}"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.WARNING: [Calendar] Sync failed {"calendarId":"a33076c1-8d97-431a-99f0-85c9524e118b","code":400,"reason":"{
\"error\": {
\"errors\": [
{
\"domain\": \"global\",
\"reason\": \"push.webhookUrlNotHttps\",
\"message\": \"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\"
}
],
\"code\": 400,
\"message\": \"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\"
}
}"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":391,"provider":"office","responseBody":"{\"error\":\"invalid_client\",\"error_description\":\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 587224ad-f597-4371-b2ba-00fcd2da1b00 Correlation ID: 4e752610-95b1-4606-847f-68e00f90be0a Timestamp: 2026-05-28 08:28:21Z\",\"error_codes\":[7000215],\"timestamp\":\"2026-05-28 08:28:21Z\",\"trace_id\":\"587224ad-f597-4371-b2ba-00fcd2da1b00\",\"correlation_id\":\"4e752610-95b1-4606-847f-68e00f90be0a\",\"error_uri\":\"https://login.microsoftonline.com/error?code=7000215\"}"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":391,"provider":"office","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1271,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1271,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1271,"provider":"office","refreshToken":"118cde2c06993147b07ccaec4cbcd5026a819dea6c71081166a492933e392afb","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Committing…","depth":2,"bounds":{"left":0.6625665,"top":0.44134077,"width":0.06948138,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":2,"bounds":{"left":0.6625665,"top":0.47326416,"width":0.06948138,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09740692,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8374335,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"bounds":{"left":0.85272604,"top":0.019952115,"width":0.062832445,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.37632978,"top":0.10055866,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"15","depth":4,"bounds":{"left":0.3856383,"top":0.10055866,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.39694148,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.40425533,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-28 08:28:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"73199e23-a066-42ba-b189-2802e0869a44\",\"trace_id\":\"e53672c2-0f50-409d-af25-84ab485c505d\"}\n[2026-05-28 08:28:04] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"73199e23-a066-42ba-b189-2802e0869a44\",\"trace_id\":\"e53672c2-0f50-409d-af25-84ab485c505d\"}\n[2026-05-28 08:28:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"73199e23-a066-42ba-b189-2802e0869a44\",\"trace_id\":\"e53672c2-0f50-409d-af25-84ab485c505d\"}\n[2026-05-28 08:28:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"741b2c4e-6a44-4c46-b9fb-fce017aef225\",\"trace_id\":\"804dc547-eb25-4b32-8d0f-c87019773085\"}\n[2026-05-28 08:28:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"741b2c4e-6a44-4c46-b9fb-fce017aef225\",\"trace_id\":\"804dc547-eb25-4b32-8d0f-c87019773085\"}\n[2026-05-28 08:28:09] local.NOTICE: Monitoring start {\"correlation_id\":\"8ae5c131-edd9-463d-8161-875f4d34320f\",\"trace_id\":\"1b6420c8-ef4e-4566-81b2-688696064648\"}\n[2026-05-28 08:28:09] local.NOTICE: Monitoring end {\"correlation_id\":\"8ae5c131-edd9-463d-8161-875f4d34320f\",\"trace_id\":\"1b6420c8-ef4e-4566-81b2-688696064648\"}\n[2026-05-28 08:28:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"6f5390d3-abe7-4e56-a662-aeed1098941b\",\"trace_id\":\"b57dc2df-2f4d-4d3b-b09a-aa6e61205d5e\"}\n[2026-05-28 08:28:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"6f5390d3-abe7-4e56-a662-aeed1098941b\",\"trace_id\":\"b57dc2df-2f4d-4d3b-b09a-aa6e61205d5e\"}\n[2026-05-28 08:28:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"ba694158-ea28-4ac1-b134-83ac485146e0\",\"trace_id\":\"83a26b74-baa5-407e-9fc2-2b49d65b1c77\"}\n[2026-05-28 08:28:12] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"ba694158-ea28-4ac1-b134-83ac485146e0\",\"trace_id\":\"83a26b74-baa5-407e-9fc2-2b49d65b1c77\"}\n[2026-05-28 08:28:12] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"ba694158-ea28-4ac1-b134-83ac485146e0\",\"trace_id\":\"83a26b74-baa5-407e-9fc2-2b49d65b1c77\"}\n[2026-05-28 08:28:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"ba694158-ea28-4ac1-b134-83ac485146e0\",\"trace_id\":\"83a26b74-baa5-407e-9fc2-2b49d65b1c77\"}\n[2026-05-28 08:28:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"b79833c7-3eab-4eb7-98bb-42359039b8fb\",\"trace_id\":\"a8e159bc-867d-40af-bf7d-1228cf6d4f16\"}\n[2026-05-28 08:28:14] local.INFO: Running conference:monitor:count command for activities in (2026-05-28 08:26:00, 2026-05-28 08:28:00] {\"correlation_id\":\"b79833c7-3eab-4eb7-98bb-42359039b8fb\",\"trace_id\":\"a8e159bc-867d-40af-bf7d-1228cf6d4f16\"}\n[2026-05-28 08:28:14] local.INFO: [conference:monitor:count] No activities found in (2026-05-28 08:26:00, 2026-05-28 08:28:00] {\"correlation_id\":\"b79833c7-3eab-4eb7-98bb-42359039b8fb\",\"trace_id\":\"a8e159bc-867d-40af-bf7d-1228cf6d4f16\"}\n[2026-05-28 08:28:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"b79833c7-3eab-4eb7-98bb-42359039b8fb\",\"trace_id\":\"a8e159bc-867d-40af-bf7d-1228cf6d4f16\"}\n[2026-05-28 08:28:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"d51071d5-ead0-45f0-a07e-e3234074f884\",\"trace_id\":\"77173d9f-596f-405f-ae55-ba117b66455d\"}\n[2026-05-28 08:28:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"calendar:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.NOTICE: Calendar sync start {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"d51071d5-ead0-45f0-a07e-e3234074f884\",\"trace_id\":\"77173d9f-596f-405f-ae55-ba117b66455d\"}\n[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1393,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1393,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1393,\"provider\":\"google\",\"refreshToken\":\"5aa7e2d96b53201cd16fca5d2e4ef3ad03320971fc064781d18aee3ae7b99fbf\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1393,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1393,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1387,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1387,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1387,\"provider\":\"google\",\"refreshToken\":\"8157ac6de94842937194009e9c50e459253600f799dacf6a40755ffdbeb5bba6\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1387,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1387,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1348,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1348,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1348,\"provider\":\"google\",\"refreshToken\":\"9e7d13d3032d0cb1b79d8e95aef01383e8e91eb52ff8ee960c8a0b6b95cd8c73\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1348,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1348,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1361,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1361,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1361,\"provider\":\"google\",\"refreshToken\":\"6c843da199c2b9907445329304fcc4ec5057a4ee748d8299641764395c08e1fd\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1361,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1361,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1310,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1310,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1310,\"provider\":\"google\",\"refreshToken\":\"e34818922c2830a660813a63f6169a4a9a992ae2cccd7dc8dd7796cfdb470ef1\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1310,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1310,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1333,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1333,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1333,\"provider\":\"google\",\"refreshToken\":\"6c902986546d8e8da1dc539b046cdc1d458f519acc972e5b5f1d6a1a295165e0\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1333,\"provider\":\"google\",\"responseBody\":{\"error\":\"unauthorized_client\",\"error_description\":\"Unauthorized\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1333,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1368,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1368,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1368,\"provider\":\"google\",\"refreshToken\":\"d2f128898ff8543bd16b69cfae37896ab85119b0f5ed2b431d739593bb600333\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1368,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1368,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1365,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1365,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1365,\"provider\":\"google\",\"refreshToken\":\"7676e4a9afcd082b413248ab5ec6e487021fec6a9bdf315860a59cefad9caad8\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1365,\"provider\":\"google\",\"responseBody\":{\"error\":\"unauthorized_client\",\"error_description\":\"Unauthorized\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1365,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1364,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1364,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1364,\"provider\":\"google\",\"refreshToken\":\"dd5882ebce76e645292ce33ae74238abbb77c0a4ecc6a2bfe723cad82e72ba8e\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1364,\"provider\":\"google\",\"responseBody\":{\"error\":\"unauthorized_client\",\"error_description\":\"Unauthorized\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1364,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1370,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1370,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1370,\"provider\":\"office\",\"refreshToken\":\"b7ee8035306d0043cea6e00e7c4fe14f745e44074a1194db62a31cdf8b70af3e\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1370,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 41d8db5c-a91f-41a6-9b5c-22a6c99b9100 Correlation ID: 70bc0a6f-1565-4e74-94dc-419d94108fa9 Timestamp: 2026-05-28 08:28:18Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:18Z\\\",\\\"trace_id\\\":\\\"41d8db5c-a91f-41a6-9b5c-22a6c99b9100\\\",\\\"correlation_id\\\":\\\"70bc0a6f-1565-4e74-94dc-419d94108fa9\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1370,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1202,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1202,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1202,\"provider\":\"office\",\"refreshToken\":\"b458799ccc29b21a6e2eb5260fdb63e49ccba21bf942a3973fb63799bd7f0afe\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1202,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: d3d14dfc-1b70-40c4-b9db-fab12f748300 Correlation ID: 4c5f746c-8366-44c1-8733-6877607826db Timestamp: 2026-05-28 08:28:19Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:19Z\\\",\\\"trace_id\\\":\\\"d3d14dfc-1b70-40c4-b9db-fab12f748300\\\",\\\"correlation_id\\\":\\\"4c5f746c-8366-44c1-8733-6877607826db\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1202,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: Calendar sync job dispatched {\"calendar_id\":501} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1300,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1300,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1300,\"provider\":\"google\",\"refreshToken\":\"4b811db0725fd9602a95943519a7da935e2a5065da7d9ebfcb170752e3e1ddb8\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1300,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1300,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1409,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1409,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1409,\"provider\":\"google\",\"refreshToken\":\"e2a3f2d06894894eed1ee87d9db1ace77d4d42ee6e1288a8940ad2c10333b0c4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1409,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1409,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1352,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1352,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1352,\"provider\":\"google\",\"refreshToken\":\"dd4b16b00fdc1216da6b717c02338c073636e29162826b2de6db3f064fc029eb\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1352,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1352,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1296,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1296,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1296,\"provider\":\"office\",\"refreshToken\":\"011ae723c9d800c674e0b4be76f49fc046dac7d501b66c59ef0d9549cfa56ae5\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [Calendar] Processing sync {\"calendarId\":\"a33076c1-8d97-431a-99f0-85c9524e118b\",\"from\":null,\"to\":null,\"delta\":\"CIiFh8TP44kDEIiFh8TP44kDGAUgkZvkzgIokZvkzgI=\",\"last_sync\":\"2024-12-09 07:12:53\",\"dateMode\":\"daily\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"integration-app\",\"crm_owner\":1695,\"team_id\":3143} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1296,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: dd83a147-95bc-407c-8c9b-3c14e7cb7d00 Correlation ID: bb16bae3-b3c4-467e-bd95-4e7ab85364c9 Timestamp: 2026-05-28 08:28:20Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:20Z\\\",\\\"trace_id\\\":\\\"dd83a147-95bc-407c-8c9b-3c14e7cb7d00\\\",\\\"correlation_id\\\":\\\"bb16bae3-b3c4-467e-bd95-4e7ab85364c9\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1296,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":391,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":391,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":391,\"provider\":\"office\",\"refreshToken\":\"00045eebae0f39b34887c6d53f92ae78064f7145e1f4b67754aebd03cfb2d881\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [Google Calendar] Failed to watch channel for calendar {\"calendarId\":\"a33076c1-8d97-431a-99f0-85c9524e118b\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.WARNING: [Calendar] Sync failed {\"calendarId\":\"a33076c1-8d97-431a-99f0-85c9524e118b\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":391,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 587224ad-f597-4371-b2ba-00fcd2da1b00 Correlation ID: 4e752610-95b1-4606-847f-68e00f90be0a Timestamp: 2026-05-28 08:28:21Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:21Z\\\",\\\"trace_id\\\":\\\"587224ad-f597-4371-b2ba-00fcd2da1b00\\\",\\\"correlation_id\\\":\\\"4e752610-95b1-4606-847f-68e00f90be0a\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":391,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1271,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1271,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1271,\"provider\":\"office\",\"refreshToken\":\"118cde2c06993147b07ccaec4cbcd5026a819dea6c71081166a492933e392afb\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1271,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: dd8bf2a7-bc49-43d7-a487-892c51e27600 Correlation ID: 51e3eb6c-c47e-4dd7-91aa-e734fe5b65cf Timestamp: 2026-05-28 08:28:21Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:21Z\\\",\\\"trace_id\\\":\\\"dd8bf2a7-bc49-43d7-a487-892c51e27600\\\",\\\"correlation_id\\\":\\\"51e3eb6c-c47e-4dd7-91aa-e734fe5b65cf\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1271,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1351,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1351,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1351,\"provider\":\"google\",\"refreshToken\":\"4271d15b9e60a606439caddc68337f783e472c85b03dacff14d1b6dfded9051c\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1351,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1351,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1366,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1366,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1366,\"provider\":\"google\",\"refreshToken\":\"ae21385059b2eebfd43f68aecd56eccd702a1aabb6598f1f7ab594ed8af491b4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1366,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1366,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: Calendar sync job dispatched {\"calendar_id\":378} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: Calendar sync job dispatched {\"calendar_id\":504} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.NOTICE: Calendar sync end {\"retrieved_calendars\":31,\"processed_calendars\":3} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"calendar:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [Calendar] Processing sync {\"calendarId\":\"2676cb6d-f86c-427e-bf78-591e388e3c1e\",\"from\":null,\"to\":null,\"delta\":\"CJ_x49O3jpIDEJ_x49O3jpIDGAUgw67KlwMow67KlwM=\",\"last_sync\":\"2026-01-19 07:48:40\",\"dateMode\":\"daily\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.WARNING: [Pipedrive] Account not connected for user {\"userId\":\"e6538737-e7b4-455f-a37a-3e79b665a220\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":1116,\"sociable_id\":241,\"provider_user_id\":\"19555731\",\"expires\":1779091997,\"refresh_token_expires\":null,\"provider\":\"pipedrive\",\"state\":\"full-refresh\",\"auth_scope\":\"base,deals:full,activities:full,contacts:full,search:read\",\"retry_after\":null,\"created_at\":\"2023-09-08 09:44:29\",\"updated_at\":\"2026-05-18 08:13:32\"}}} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"pipedrive\",\"crm_owner\":241,\"team_id\":19} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"pipedrive\",\"team_id\":19} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"pipedrive\",\"team_id\":19} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.WARNING: [Calendar] CRM disconnected for user so events will not be matched {\"provider\":\"pipedrive\",\"user_id\":241,\"message\":\"Your Pipedrive account has become disconnected. Please login to Jiminny to reconnect.\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [Google Calendar] Failed to watch channel for calendar {\"calendarId\":\"2676cb6d-f86c-427e-bf78-591e388e3c1e\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.WARNING: [Calendar] Sync failed {\"calendarId\":\"2676cb6d-f86c-427e-bf78-591e388e3c1e\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [Calendar] Processing sync {\"calendarId\":\"9e8b1a2c-1a8f-42bd-b161-810fc0baf540\",\"from\":null,\"to\":null,\"delta\":\"R0usmcdvmMuZCBYV0hguCBhf4uKqyU9_gdNd-le_nqqau95XAUmZwlIAy2uwtCf5sA67w6NIiDvawUSmVjpTzZO-RsxLdeS-g8Kxy6ODZQxAxafq8AJNx0hJV7T291NUvfaPYqLMv-3je3IdhAPUtXQXkHtYaBAlX_DDBxwc3zYoVVQ8iM9mQkBykdA3sh-KVYPyzi7nK4cZg5Jzpu9tHA.UA7urx3pJyhUhdo_16STIbSNXUrF-qeQVIis9stVUeY\",\"last_sync\":\"2026-05-28 07:44:06\",\"dateMode\":\"daily\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":89,\"team_id\":2} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [MS Office Calendar] Skipping delta sync for daily mode {\"calendarId\":\"9e8b1a2c-1a8f-42bd-b161-810fc0baf540\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:29:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"86a65904-a9f8-43c9-b0c3-1e9c8b4b9541\",\"trace_id\":\"800b02ff-3553-46a3-a8c6-c12324a1ce53\"}\n[2026-05-28 08:29:05] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"86a65904-a9f8-43c9-b0c3-1e9c8b4b9541\",\"trace_id\":\"800b02ff-3553-46a3-a8c6-c12324a1ce53\"}\n[2026-05-28 08:29:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"86a65904-a9f8-43c9-b0c3-1e9c8b4b9541\",\"trace_id\":\"800b02ff-3553-46a3-a8c6-c12324a1ce53\"}\n[2026-05-28 08:29:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"e5162656-5b49-4857-9917-f0cf3ddffe27\",\"trace_id\":\"a3a53cc5-596d-474c-b9c4-f6c5f7ebdfd0\"}\n[2026-05-28 08:29:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"e5162656-5b49-4857-9917-f0cf3ddffe27\",\"trace_id\":\"a3a53cc5-596d-474c-b9c4-f6c5f7ebdfd0\"}\n[2026-05-28 08:29:09] local.NOTICE: Monitoring start {\"correlation_id\":\"f559463e-0c12-46df-8b53-0c50cf4aa3eb\",\"trace_id\":\"5a09aee9-5f75-4bfa-93e4-df0ff76f2326\"}\n[2026-05-28 08:29:09] local.NOTICE: Monitoring end {\"correlation_id\":\"f559463e-0c12-46df-8b53-0c50cf4aa3eb\",\"trace_id\":\"5a09aee9-5f75-4bfa-93e4-df0ff76f2326\"}\n[2026-05-28 08:29:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"9b1cc2f1-0c8a-4aa0-a9e8-57ac879839e4\",\"trace_id\":\"d69dd133-b5f0-4568-81ef-9cce3d1c5c9e\"}\n[2026-05-28 08:29:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"9b1cc2f1-0c8a-4aa0-a9e8-57ac879839e4\",\"trace_id\":\"d69dd133-b5f0-4568-81ef-9cce3d1c5c9e\"}\n[2026-05-28 08:29:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"87e10603-9e6f-4d71-97ab-5ba67103e5fd\",\"trace_id\":\"0aae0afb-779f-4999-892d-0188e14b3dcb\"}\n[2026-05-28 08:29:12] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"87e10603-9e6f-4d71-97ab-5ba67103e5fd\",\"trace_id\":\"0aae0afb-779f-4999-892d-0188e14b3dcb\"}\n[2026-05-28 08:29:12] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"87e10603-9e6f-4d71-97ab-5ba67103e5fd\",\"trace_id\":\"0aae0afb-779f-4999-892d-0188e14b3dcb\"}\n[2026-05-28 08:29:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"87e10603-9e6f-4d71-97ab-5ba67103e5fd\",\"trace_id\":\"0aae0afb-779f-4999-892d-0188e14b3dcb\"}\n[2026-05-28 08:30:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"200b132b-d8db-4010-b968-fe5e3fcc42f1\",\"trace_id\":\"7457715a-3b9d-4c35-a499-455c83e925ab\"}\n[2026-05-28 08:30:04] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"200b132b-d8db-4010-b968-fe5e3fcc42f1\",\"trace_id\":\"7457715a-3b9d-4c35-a499-455c83e925ab\"}\n[2026-05-28 08:30:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"200b132b-d8db-4010-b968-fe5e3fcc42f1\",\"trace_id\":\"7457715a-3b9d-4c35-a499-455c83e925ab\"}\n[2026-05-28 08:30:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"a94ef973-dee7-4bdf-99aa-9ff06f5a5561\",\"trace_id\":\"4e37013f-2993-4c71-87d9-560f8f429d27\"}\n[2026-05-28 08:30:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"a94ef973-dee7-4bdf-99aa-9ff06f5a5561\",\"trace_id\":\"4e37013f-2993-4c71-87d9-560f8f429d27\"}\n[2026-05-28 08:30:07] local.NOTICE: Monitoring start {\"correlation_id\":\"691e7103-784d-4b4a-8036-f3c624a186db\",\"trace_id\":\"991dd947-ed80-4080-8769-8ee7efc4e6a4\"}\n[2026-05-28 08:30:07] local.NOTICE: Monitoring end {\"correlation_id\":\"691e7103-784d-4b4a-8036-f3c624a186db\",\"trace_id\":\"991dd947-ed80-4080-8769-8ee7efc4e6a4\"}\n[2026-05-28 08:30:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"00cf8914-d440-4826-a079-ee4586e76c62\",\"trace_id\":\"d77009ee-8d7b-44ae-bb21-2080b6d48c6c\"}\n[2026-05-28 08:30:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"00cf8914-d440-4826-a079-ee4586e76c62\",\"trace_id\":\"d77009ee-8d7b-44ae-bb21-2080b6d48c6c\"}\n[2026-05-28 08:30:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"7c9550d0-42ed-4b1d-b5b3-7dca67f743ec\",\"trace_id\":\"84177853-9530-4b1e-bde6-3dc0c71883ee\"}\n[2026-05-28 08:30:10] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"7c9550d0-42ed-4b1d-b5b3-7dca67f743ec\",\"trace_id\":\"84177853-9530-4b1e-bde6-3dc0c71883ee\"}\n[2026-05-28 08:30:10] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"7c9550d0-42ed-4b1d-b5b3-7dca67f743ec\",\"trace_id\":\"84177853-9530-4b1e-bde6-3dc0c71883ee\"}\n[2026-05-28 08:30:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"7c9550d0-42ed-4b1d-b5b3-7dca67f743ec\",\"trace_id\":\"84177853-9530-4b1e-bde6-3dc0c71883ee\"}\n[2026-05-28 08:30:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"85cc6c92-262b-45c5-bbcc-4a084137fde3\",\"trace_id\":\"058bc9a3-67af-49b6-a87c-8a0a0bc0c47a\"}\n[2026-05-28 08:30:12] local.INFO: Running conference:monitor:count command for activities in (2026-05-28 08:28:00, 2026-05-28 08:30:00] {\"correlation_id\":\"85cc6c92-262b-45c5-bbcc-4a084137fde3\",\"trace_id\":\"058bc9a3-67af-49b6-a87c-8a0a0bc0c47a\"}\n[2026-05-28 08:30:12] local.INFO: [conference:monitor:count] No activities found in (2026-05-28 08:28:00, 2026-05-28 08:30:00] {\"correlation_id\":\"85cc6c92-262b-45c5-bbcc-4a084137fde3\",\"trace_id\":\"058bc9a3-67af-49b6-a87c-8a0a0bc0c47a\"}\n[2026-05-28 08:30:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"85cc6c92-262b-45c5-bbcc-4a084137fde3\",\"trace_id\":\"058bc9a3-67af-49b6-a87c-8a0a0bc0c47a\"}\n[2026-05-28 08:30:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"5083d024-d669-4c6a-bde3-ce084d6a628c\",\"trace_id\":\"83110e1f-4309-4f4a-b8bb-eab5c0ec081e\"}\n[2026-05-28 08:30:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"5083d024-d669-4c6a-bde3-ce084d6a628c\",\"trace_id\":\"83110e1f-4309-4f4a-b8bb-eab5c0ec081e\"}\n[2026-05-28 08:30:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"bc529b16-9502-4df3-b2c0-c63fcf977ed5\",\"trace_id\":\"9dd5d6d0-4cc5-454c-a0c8-0e72b69eeb29\"}\n[2026-05-28 08:30:15] local.INFO: [TextRelayService] Starting sync {\"mailbox\":\"catch-all@txt.staging.jiminny.com\",\"expected_alias\":\"catch-all\",\"expected_host\":\"txt.staging.jiminny.com\"} {\"correlation_id\":\"bc529b16-9502-4df3-b2c0-c63fcf977ed5\",\"trace_id\":\"9dd5d6d0-4cc5-454c-a0c8-0e72b69eeb29\"}\n[2026-05-28 08:30:15] local.INFO: [TextRelayService] Sync completed {\"mailbox\":\"catch-all@txt.staging.jiminny.com\",\"messages_processed\":0,\"message_ids\":[]} {\"correlation_id\":\"bc529b16-9502-4df3-b2c0-c63fcf977ed5\",\"trace_id\":\"9dd5d6d0-4cc5-454c-a0c8-0e72b69eeb29\"}\n[2026-05-28 08:30:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"bc529b16-9502-4df3-b2c0-c63fcf977ed5\",\"trace_id\":\"9dd5d6d0-4cc5-454c-a0c8-0e72b69eeb29\"}\n[2026-05-28 08:30:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"b655bca8-effa-420b-8686-95ba96f27085\",\"trace_id\":\"b1f43a19-c7ad-428e-9933-4e509b5f0055\"}\n[2026-05-28 08:30:18] local.INFO: Running pre-meeting notification command {\"correlation_id\":\"b655bca8-effa-420b-8686-95ba96f27085\",\"trace_id\":\"b1f43a19-c7ad-428e-9933-4e509b5f0055\"}\n[2026-05-28 08:30:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"b655bca8-effa-420b-8686-95ba96f27085\",\"trace_id\":\"b1f43a19-c7ad-428e-9933-4e509b5f0055\"}\n[2026-05-28 08:30:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"5a8493c4-3ef7-4453-98b7-f32225d453fe\",\"trace_id\":\"056f1aea-8825-4e2c-8239-7804086e504e\"}\n[2026-05-28 08:30:20] local.INFO: Running conference:monitor:start command for activities in (2026-05-28 08:20:00, 2026-05-28 08:25:00] {\"correlation_id\":\"5a8493c4-3ef7-4453-98b7-f32225d453fe\",\"trace_id\":\"056f1aea-8825-4e2c-8239-7804086e504e\"}\n[2026-05-28 08:30:20] local.INFO: [conference:monitor:start] No activities found in (2026-05-28 08:20:00, 2026-05-28 08:25:00] {\"correlation_id\":\"5a8493c4-3ef7-4453-98b7-f32225d453fe\",\"trace_id\":\"056f1aea-8825-4e2c-8239-7804086e504e\"}\n[2026-05-28 08:30:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"5a8493c4-3ef7-4453-98b7-f32225d453fe\",\"trace_id\":\"056f1aea-8825-4e2c-8239-7804086e504e\"}\n[2026-05-28 08:30:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"18a2aed9-1aae-4b10-a7fa-f75a147db499\",\"trace_id\":\"fff0c9b2-1c60-4402-b30a-2f41d9b45db3\"}\n[2026-05-28 08:30:22] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesEnded {\"from\":\"08:25\",\"to\":\"08:30\"} {\"correlation_id\":\"18a2aed9-1aae-4b10-a7fa-f75a147db499\",\"trace_id\":\"fff0c9b2-1c60-4402-b30a-2f41d9b45db3\"}\n[2026-05-28 08:30:22] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesWithUnfinishedSession {\"from\":\"22:20\",\"to\":\"22:25\"} {\"correlation_id\":\"18a2aed9-1aae-4b10-a7fa-f75a147db499\",\"trace_id\":\"fff0c9b2-1c60-4402-b30a-2f41d9b45db3\"}\n[2026-05-28 08:30:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"18a2aed9-1aae-4b10-a7fa-f75a147db499\",\"trace_id\":\"fff0c9b2-1c60-4402-b30a-2f41d9b45db3\"}\n[2026-05-28 08:30:23] local.NOTICE: Repairing HubSpot tokens start {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:23] local.INFO: Trying to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:23] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:23] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":59,\"provider\":\"hubspot\",\"refreshToken\":\"97b78f6e2cc49965c00c2492b602b02708b1392551e6b3f113fbaa48992af90b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:26] local.ERROR: Failed to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:26] local.INFO: Trying to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:26] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:26] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":306,\"provider\":\"hubspot\",\"refreshToken\":\"6fa6aa8cc641d131231acc3470f5c03cb3b07b2e580fb18f8acb3b1dbb72549b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.ERROR: Failed to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.INFO: Trying to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1372,\"provider\":\"hubspot\",\"refreshToken\":\"9aa73948c761da29dce46c177cf9aee1fde483a44169ca38723f9f0597d7a8c4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.ERROR: Failed to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.NOTICE: Repairing HubSpot tokens end {\"total\":3,\"fixed\":0,\"failed\":3} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"jiminny:transcription:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"f73071c7-8696-459f-8aff-e61a7c6b30e6\",\"trace_id\":\"d72fc2ce-5064-4877-b401-10891378e1bc\"}\n[2026-05-28 08:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"720d5c87-3d13-4193-87c9-efb8dc6df7c8\",\"trace_id\":\"a9d9c9fe-db29-44a1-a5f6-1905d48dde90\"}\n[2026-05-28 08:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"jiminny:transcription:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"f73071c7-8696-459f-8aff-e61a7c6b30e6\",\"trace_id\":\"d72fc2ce-5064-4877-b401-10891378e1bc\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Command] Starting polling service {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] Service starting {\"memory_limit\":\"256M\",\"max_execution_time\":\"0\",\"initial_memory_mb\":62.0} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] Acquired polling lock {\"expires_at\":\"2026-05-28T08:32:33.444809Z\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"720d5c87-3d13-4193-87c9-efb8dc6df7c8\",\"trace_id\":\"a9d9c9fe-db29-44a1-a5f6-1905d48dde90\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:35] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:reset-governor\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"c692a62b-3b1a-4ff3-b965-388a7d12f619\",\"trace_id\":\"d1bdfdec-73bd-499f-a31e-b25a864da976\"}\n[2026-05-28 08:30:35] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:reset-governor\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"c692a62b-3b1a-4ff3-b965-388a7d12f619\",\"trace_id\":\"d1bdfdec-73bd-499f-a31e-b25a864da976\"}\n[2026-05-28 08:30:38] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:38] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:38] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:39] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814238,\"provider\":\"twilio-flex\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814239,\"provider\":\"xant\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814240,\"provider\":\"apollo\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814241,\"provider\":\"groove\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814242,\"provider\":\"twilio-video\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814243,\"provider\":\"hubspot\",\"team\":\"hubspot\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:fail-stalled\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"f6d797df-5275-4cf1-8ddd-300c125df8da\",\"trace_id\":\"2b46c31f-aced-4324-a70a-6395f0a72618\"}\n[2026-05-28 08:30:42] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:fail-stalled\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"f6d797df-5275-4cf1-8ddd-300c125df8da\",\"trace_id\":\"2b46c31f-aced-4324-a70a-6395f0a72618\"}\n[2026-05-28 08:30:42] local.WARNING: [Salesforce] Account not connected for user {\"userId\":\"cdf8b554-d951-4758-bc2b-c1b85d1cd0b9\",\"account\":null} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"salesforce\",\"crm_owner\":3,\"team_id\":1} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [CrmOwnerResolver] TeamMember found with active crm connection {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1194,\"provider\":\"twilio-flex\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1194,\"provider\":\"twilio-flex\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SyncActivity] Start {\"import_id\":814238,\"provider\":\"twilio-flex\",\"provider_id\":317,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.NOTICE: [TwilioFlex] Calls import start {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.ALERT: [SyncActivity] Failed {\"import_id\":814238,\"provider\":\"twilio-flex\",\"provider_id\":317,\"team\":\"jiminny\",\"team_id\":1,\"reason\":\"[HTTP 401] Unable to fetch page: Authenticate\",\"file\":\"/home/jiminny/vendor/twilio/sdk/src/Twilio/Page.php\",\"line\":60} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SyncActivity] Start {\"import_id\":814239,\"provider\":\"xant\",\"provider_id\":161,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [Salesforce] Performing query {\"query\":\"\n SELECT Playbooks_Call_Date__c,Playbooks_Call_Recording__c,CreatedDate,TaskSubtype,CallType,CallDurationInSeconds,Id,OwnerId,WhoId,WhatId,Priority,ActivityDate,Subject,Description,Status,Type\n FROM Task\n WHERE IsDeleted = false\n AND LastModifiedDate >= :from\n AND LastModifiedDate <= :to\n ORDER BY LastModifiedDate ASC\n LIMIT :limit\",\"params\":{\"from\":\"2026-05-28T08:14:00Z\",\"to\":\"2026-05-28T08:30:00Z\",\"ownerId\":null,\"subType\":null,\"limit\":5000}} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [Salesforce] Sending request {\"endpoint\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=%0A++++++++++++SELECT+Playbooks_Call_Date__c%2CPlaybooks_Call_Recording__c%2CCreatedDate%2CTaskSubtype%2CCallType%2CCallDurationInSeconds%2CId%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%0A++++++++++++++FROM+Task%0A+++++++++++++WHERE+IsDeleted+%3D+false%0A+++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A+++++++++++++++AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z%0A++++++++++ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000 GET\",\"team_id\":1} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:44] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:44] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:44] local.INFO: [Xant (InsideSales)] No calls found. {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] End {\"import_id\":814239,\"provider\":\"xant\",\"provider_id\":161,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Memory usage {\"import_id\":814239,\"provider\":\"xant\",\"provider_id\":161,\"team\":\"jiminny\",\"team_id\":1,\"memory_usage\":24080216,\"memory_real_usage\":65011712,\"pid\":21708} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Start {\"import_id\":814240,\"provider\":\"apollo\",\"provider_id\":441,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Performing query {\"query\":\"\n SELECT AccountId,CreatedDate,TaskSubtype,CallType,Id,OwnerId,WhoId,WhatId,Priority,ActivityDate,Subject,Description,Status,Type\n FROM Task\n WHERE IsDeleted = false\n AND LastModifiedDate >= :from\n AND LastModifiedDate <= :to\n ORDER BY LastModifiedDate ASC\n LIMIT :limit\",\"params\":{\"from\":\"2026-05-28T08:14:00Z\",\"to\":\"2026-05-28T08:30:00Z\",\"ownerId\":null,\"subType\":null,\"limit\":5000}} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Sending request {\"endpoint\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=%0A++++++++++++SELECT+AccountId%2CCreatedDate%2CTaskSubtype%2CCallType%2CId%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%0A++++++++++++++FROM+Task%0A+++++++++++++WHERE+IsDeleted+%3D+false%0A+++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A+++++++++++++++AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z%0A++++++++++ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000 GET\",\"team_id\":1} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Apollo] No calls found. {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] End {\"import_id\":814240,\"provider\":\"apollo\",\"provider_id\":441,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Memory usage {\"import_id\":814240,\"provider\":\"apollo\",\"provider_id\":441,\"team\":\"jiminny\",\"team_id\":1,\"memory_usage\":24242184,\"memory_real_usage\":65011712,\"pid\":21708} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Start {\"import_id\":814241,\"provider\":\"groove\",\"provider_id\":228,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Performing query {\"query\":\"\n SELECT call_recording_url__c,TaskSubtype,CreatedDate,CallType,CallDurationInSeconds,Id,OwnerId,WhoId,WhatId,Priority,ActivityDate,Subject,Description,Status,Type\n FROM Task\n WHERE IsDeleted = false\n AND LastModifiedDate >= :from\n AND LastModifiedDate <= :to\n ORDER BY LastModifiedDate ASC\n LIMIT :limit\",\"params\":{\"from\":\"2026-05-28T08:14:00Z\",\"to\":\"2026-05-28T08:30:00Z\",\"ownerId\":null,\"subType\":null,\"limit\":5000}} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Sending request {\"endpoint\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=%0A++++++++++++SELECT+call_recording_url__c%2CTaskSubtype%2CCreatedDate%2CCallType%2CCallDurationInSeconds%2CId%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%0A++++++++++++++FROM+Task%0A+++++++++++++WHERE+IsDeleted+%3D+false%0A+++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A+++++++++++++++AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z%0A++++++++++ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000 GET\",\"team_id\":1} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"b2b37795-cfa8-472a-b681-322ce27c0e08\",\"trace_id\":\"605e54f2-d4f9-4683-b3fd-6c1c23e691b7\"}\n[2026-05-28 08:30:44] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"b2b37795-cfa8-472a-b681-322ce27c0e08\",\"trace_id\":\"605e54f2-d4f9-4683-b3fd-6c1c23e691b7\"}\n[2026-05-28 08:30:44] local.ERROR: [Salesforce] Request exception [400] \nSELECT call_recording_url__c,TaskSubtype\n ^\nERROR at Row:1:Column:8\nNo such column 'call_recording_url__c' on entity 'Task'. If you are attempting to use a custom field, be sure to append the '__c' after the custom field name. Please reference your WSDL or the describe call for the appropriate names. {\"url\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=%0A++++++++++++SELECT+call_recording_url__c%2CTaskSubtype%2CCreatedDate%2CCallType%2CCallDurationInSeconds%2CId%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%0A++++++++++++++FROM+Task%0A+++++++++++++WHERE+IsDeleted+%3D+false%0A+++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A+++++++++++++++AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z%0A++++++++++ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000\",\"data\":{\"headers\":{\"Authorization\":\"Bearer 00D2g0000008hH4!AQEAQHWUK6nshi8dSCX9CJphxkVivcv_TK98TLOckVy4i0Z1gQfAoRRuH2LVwDXDkbTPs80wvQjczjAlOz0UEtbHoORBLi2u\"}},\"response\":{\"GuzzleHttp\\\\Psr7\\\\Stream\":\"[{\\\"message\\\":\\\"\\\\nSELECT call_recording_url__c,TaskSubtype\\\\n ^\\\\nERROR at Row:1:Column:8\\\\nNo such column 'call_recording_url__c' on entity 'Task'. If you are attempting to use a custom field, be sure to append the '__c' after the custom field name. Please reference your WSDL or the describe call for the appropriate names.\\\",\\\"errorCode\\\":\\\"INVALID_FIELD\\\"}]\"},\"fields\":[]} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.ALERT: [SyncActivity] Failed {\"import_id\":814241,\"provider\":\"groove\",\"provider_id\":228,\"team\":\"jiminny\",\"team_id\":1,\"reason\":\"\nSELECT call_recording_url__c,TaskSubtype\n ^\nERROR at Row:1:Column:8\nNo such column 'call_recording_url__c' on entity 'Task'. If you are attempting to use a custom field, be sure to append the '__c' after the custom field name. Please reference your WSDL or the describe call for the appropriate names.\",\"file\":\"/home/jiminny/app/Services/Crm/Salesforce/Client.php\",\"line\":564} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Start {\"import_id\":814242,\"provider\":\"twilio-video\",\"provider_id\":243,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Performing query {\"query\":\"SELECT Id,OwnerId,WhoId,WhatId,Priority,ActivityDate,Subject,Description,Status,Type,twilio_call_sid__c,Lead_UUID__c,Opportunity__c\n FROM Task\n WHERE Type = 'Video'\n AND isClosed = true\n AND IsDeleted = false\n AND LastModifiedDate >= :from\n AND twilio_call_sid__c != NULL AND LastModifiedDate <= :to ORDER BY LastModifiedDate ASC\n LIMIT :limit\",\"params\":{\"from\":\"2026-05-28T08:14:00Z\",\"to\":\"2026-05-28T08:30:00Z\",\"ownerId\":null,\"subType\":null,\"limit\":5000}} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Sending request {\"endpoint\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=SELECT+Id%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%2Ctwilio_call_sid__c%2CLead_UUID__c%2COpportunity__c%0A++++++++++++++FROM+Task%0A++++++++++++WHERE+Type+%3D+%27Video%27%0A++++++++++++++AND+isClosed+%3D+true%0A++++++++++++++AND+IsDeleted+%3D+false%0A++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A++++++++++++++AND+twilio_call_sid__c+%21%3D+NULL+AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z+ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000 GET\",\"team_id\":1} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [Twilio Video] No calls found. {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] End {\"import_id\":814242,\"provider\":\"twilio-video\",\"provider_id\":243,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] Memory usage {\"import_id\":814242,\"provider\":\"twilio-video\",\"provider_id\":243,\"team\":\"jiminny\",\"team_id\":1,\"memory_usage\":24634032,\"memory_real_usage\":65011712,\"pid\":21708} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":89,\"team_id\":2} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":408,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":408,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] Start {\"import_id\":814243,\"provider\":\"hubspot\",\"provider_id\":31,\"team\":\"hubspot\",\"team_id\":2} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [HubSpot] Search calls for period {\"from\":\"2026-05-28 08:14:00\",\"to\":\"2026-05-28 08:30:00\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] End {\"import_id\":814243,\"provider\":\"hubspot\",\"provider_id\":31,\"team\":\"hubspot\",\"team_id\":2} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] Memory usage {\"import_id\":814243,\"provider\":\"hubspot\",\"provider_id\":31,\"team\":\"hubspot\",\"team_id\":2,\"memory_usage\":24947696,\"memory_real_usage\":65011712,\"pid\":21708} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:46] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"nudges:send\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"f3e257b6-82bb-440c-bf76-855ac528e4e8\",\"trace_id\":\"f8a31218-7290-45ac-8fe1-ffb1b8527521\"}\n[2026-05-28 08:30:46] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"nudges:send\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"f3e257b6-82bb-440c-bf76-855ac528e4e8\",\"trace_id\":\"f8a31218-7290-45ac-8fe1-ffb1b8527521\"}\n[2026-05-28 08:30:50] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"jiminny:playlists:normalize-sort\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"a64b1836-79a1-41da-a4b0-bc0a9703a94b\",\"trace_id\":\"c53faedc-a7a7-41b7-8e51-e84dc2755d79\"}\n[2026-05-28 08:30:50] local.INFO: [Jiminny\\Component\\Playlist\\Command\\NormalizeSortCommand::handle] starting. {\"playlists\":[]} {\"correlation_id\":\"a64b1836-79a1-41da-a4b0-bc0a9703a94b\",\"trace_id\":\"c53faedc-a7a7-41b7-8e51-e84dc2755d79\"}\n[2026-05-28 08:30:50] local.INFO: [Jiminny\\Component\\Playlist\\Command\\NormalizeSortCommand::handle] finished. {\"normalizedPlaylists\":[],\"deletedPlaylists\":[]} {\"correlation_id\":\"a64b1836-79a1-41da-a4b0-bc0a9703a94b\",\"trace_id\":\"c53faedc-a7a7-41b7-8e51-e84dc2755d79\"}\n[2026-05-28 08:30:50] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"jiminny:playlists:normalize-sort\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"a64b1836-79a1-41da-a4b0-bc0a9703a94b\",\"trace_id\":\"c53faedc-a7a7-41b7-8e51-e84dc2755d79\"}\n[2026-05-28 08:30:59] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:59] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:59] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"41db30ba-33c5-46f1-b8bd-5d9e86a70d12\",\"trace_id\":\"a5e2028d-ca41-4ba1-9ddd-a246f83ef4cc\"}\n[2026-05-28 08:31:07] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"41db30ba-33c5-46f1-b8bd-5d9e86a70d12\",\"trace_id\":\"a5e2028d-ca41-4ba1-9ddd-a246f83ef4cc\"}\n[2026-05-28 08:31:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"41db30ba-33c5-46f1-b8bd-5d9e86a70d12\",\"trace_id\":\"a5e2028d-ca41-4ba1-9ddd-a246f83ef4cc\"}\n[2026-05-28 08:31:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"f6ed0a05-caa1-4cb6-ae83-63f44ae4e0d6\",\"trace_id\":\"16cd898d-57a1-4b74-90d1-f9223bbd8d7a\"}\n[2026-05-28 08:31:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"f6ed0a05-caa1-4cb6-ae83-63f44ae4e0d6\",\"trace_id\":\"16cd898d-57a1-4b74-90d1-f9223bbd8d7a\"}\n[2026-05-28 08:31:15] local.NOTICE: Monitoring start {\"correlation_id\":\"cdf384ea-4f59-4411-8ebf-efc299e4a1c8\",\"trace_id\":\"b069d3c8-2f77-4698-bd53-97de373652e8\"}\n[2026-05-28 08:31:15] local.NOTICE: Monitoring end {\"correlation_id\":\"cdf384ea-4f59-4411-8ebf-efc299e4a1c8\",\"trace_id\":\"b069d3c8-2f77-4698-bd53-97de373652e8\"}\n[2026-05-28 08:31:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"940a264b-4aee-40a0-a527-e101ea555a38\",\"trace_id\":\"cd9169ad-4c1e-452d-b7cb-66005aae4dc8\"}\n[2026-05-28 08:31:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"940a264b-4aee-40a0-a527-e101ea555a38\",\"trace_id\":\"cd9169ad-4c1e-452d-b7cb-66005aae4dc8\"}\n[2026-05-28 08:31:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"b798f381-71f2-4c51-a135-f91f09330cfd\",\"trace_id\":\"b44ed325-23f7-4f8b-a447-4c8d0ee99d01\"}\n[2026-05-28 08:31:23] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"b798f381-71f2-4c51-a135-f91f09330cfd\",\"trace_id\":\"b44ed325-23f7-4f8b-a447-4c8d0ee99d01\"}\n[2026-05-28 08:31:24] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"b798f381-71f2-4c51-a135-f91f09330cfd\",\"trace_id\":\"b44ed325-23f7-4f8b-a447-4c8d0ee99d01\"}\n[2026-05-28 08:31:24] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"b798f381-71f2-4c51-a135-f91f09330cfd\",\"trace_id\":\"b44ed325-23f7-4f8b-a447-4c8d0ee99d01\"}\n[2026-05-28 08:31:27] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"2d631328-f2b9-44f3-83d3-613b7b9b9ddc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:27] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"2d631328-f2b9-44f3-83d3-613b7b9b9ddc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"usage\":22563136,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [HubSpot] Syncing opportunities using strategy: lastModified {\"team\":2} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.4,\"average_seconds_per_request\":0.4} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [HubSpot] Synced opportunities {\"team\":2,\"strategies\":\"lastModified\",\"sync_count\":0,\"total\":0,\"last_synced_id\":null,\"duration_ms\":432.6} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"provider\":\"hubspot\",\"status\":\"completed\",\"duration_ms\":543.02,\"usage\":22983640,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"usage\":22961848,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"2ac0447f-3c8c-4ce0-baeb-b63ddb76fa9b\",\"account\":null} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":130,\"team_id\":42} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":23.85,\"usage\":23024000,\"real_usage\":65011712,\"pid\":21703,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"usage\":22984760,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"33e34a7a-1c02-4f04-87ac-22c3a385e6e3\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":306,\"sociable_id\":109,\"provider_user_id\":\"11348452\",\"expires\":1701077403,\"refresh_token_expires\":null,\"provider\":\"hubspot\",\"state\":\"full-refresh\",\"auth_scope\":null,\"retry_after\":null,\"created_at\":\"2020-09-01 16:59:04\",\"updated_at\":\"2023-11-27 09:30:03\"}}} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":109,\"team_id\":29} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":14.98,\"usage\":23047624,\"real_usage\":65011712,\"pid\":21703,\"reason\":\"Your HubSpot account has become disconnected. Please login to Jiminny to reconnect.\"} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal Polling] Service ending {\"runtime_seconds\":56,\"total_cycles\":5,\"files_downloaded\":0,\"empty_files\":0,\"other_portal_skipped\":0,\"total_events\":0,\"events_per_file\":0,\"avg_api_ms\":192.1,\"avg_download_ms\":0.0,\"avg_transform_ms\":0.0,\"avg_process_ms\":0.0,\"peak_memory_mb\":99.88} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal Polling] Released polling lock {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"usage\":23005136,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"71e3aac5-fb66-47c5-a236-2d051ae3e319\",\"account\":null} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":256,\"team_id\":49} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":34.51,\"usage\":23021248,\"real_usage\":65011712,\"pid\":21703,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:32:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"35f98b1b-7b16-4e79-a420-7e9818097d24\",\"trace_id\":\"d66deb58-fa13-486f-a866-2cac402dc589\"}\n[2026-05-28 08:32:06] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"35f98b1b-7b16-4e79-a420-7e9818097d24\",\"trace_id\":\"d66deb58-fa13-486f-a866-2cac402dc589\"}\n[2026-05-28 08:32:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"35f98b1b-7b16-4e79-a420-7e9818097d24\",\"trace_id\":\"d66deb58-fa13-486f-a866-2cac402dc589\"}\n[2026-05-28 08:32:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"bc6784c1-c46f-4295-be09-87334f4baa39\",\"trace_id\":\"74b00236-4ed0-4464-8b07-99c328ab6461\"}\n[2026-05-28 08:32:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"bc6784c1-c46f-4295-be09-87334f4baa39\",\"trace_id\":\"74b00236-4ed0-4464-8b07-99c328ab6461\"}\n[2026-05-28 08:32:11] local.NOTICE: Monitoring start {\"correlation_id\":\"caf4d1dd-2a52-40f5-834a-f9148f642e83\",\"trace_id\":\"1312bdcc-7e8b-480a-a935-2433fb79dc70\"}\n[2026-05-28 08:32:11] local.NOTICE: Monitoring end {\"correlation_id\":\"caf4d1dd-2a52-40f5-834a-f9148f642e83\",\"trace_id\":\"1312bdcc-7e8b-480a-a935-2433fb79dc70\"}\n[2026-05-28 08:32:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"64d86889-1f0d-4f7d-a1ac-6f56e58e775e\",\"trace_id\":\"b184d66b-49f8-40ec-afbe-2e76e9c7d952\"}\n[2026-05-28 08:32:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"64d86889-1f0d-4f7d-a1ac-6f56e58e775e\",\"trace_id\":\"b184d66b-49f8-40ec-afbe-2e76e9c7d952\"}\n[2026-05-28 08:32:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"8e6dd4bc-4f44-4fb2-b2ba-9e2f385996ef\",\"trace_id\":\"7767e0ca-37a3-43a5-972e-ea9a1bedea2f\"}\n[2026-05-28 08:32:20] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"8e6dd4bc-4f44-4fb2-b2ba-9e2f385996ef\",\"trace_id\":\"7767e0ca-37a3-43a5-972e-ea9a1bedea2f\"}\n[2026-05-28 08:32:20] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"8e6dd4bc-4f44-4fb2-b2ba-9e2f385996ef\",\"trace_id\":\"7767e0ca-37a3-43a5-972e-ea9a1bedea2f\"}\n[2026-05-28 08:32:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"8e6dd4bc-4f44-4fb2-b2ba-9e2f385996ef\",\"trace_id\":\"7767e0ca-37a3-43a5-972e-ea9a1bedea2f\"}\n[2026-05-28 08:32:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"6750ab25-6dff-4e7b-9f6e-bc7d1fc4221a\",\"trace_id\":\"3db6ce9b-167d-4214-a32c-67c611aa2bbe\"}\n[2026-05-28 08:32:22] local.INFO: Running conference:monitor:count command for activities in (2026-05-28 08:30:00, 2026-05-28 08:32:00] {\"correlation_id\":\"6750ab25-6dff-4e7b-9f6e-bc7d1fc4221a\",\"trace_id\":\"3db6ce9b-167d-4214-a32c-67c611aa2bbe\"}\n[2026-05-28 08:32:22] local.INFO: [conference:monitor:count] No activities found in (2026-05-28 08:30:00, 2026-05-28 08:32:00] {\"correlation_id\":\"6750ab25-6dff-4e7b-9f6e-bc7d1fc4221a\",\"trace_id\":\"3db6ce9b-167d-4214-a32c-67c611aa2bbe\"}\n[2026-05-28 08:32:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"6750ab25-6dff-4e7b-9f6e-bc7d1fc4221a\",\"trace_id\":\"3db6ce9b-167d-4214-a32c-67c611aa2bbe\"}\n[2026-05-28 08:32:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"04510c2c-638c-4687-81d7-b12e76f41df3\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}\n[2026-05-28 08:32:23] local.INFO: [EmailSchedule] STARTING batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"04510c2c-638c-4687-81d7-b12e76f41df3\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}\n[2026-05-28 08:32:23] local.INFO: [EmailSchedule] FINISHED batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"04510c2c-638c-4687-81d7-b12e76f41df3\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}\n[2026-05-28 08:32:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"04510c2c-638c-4687-81d7-b12e76f41df3\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}\n[2026-05-28 08:32:25] local.INFO: [Jiminny\\Jobs\\Mailbox\\CreateBatches] processed 1 inboxes and created 0 batches {\"userId\":null,\"batchSize\":30,\"maxBatches\":1000} {\"correlation_id\":\"e60597ef-aca8-4bda-bb90-18f01e96874d\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}","depth":4,"bounds":{"left":0.4331782,"top":0.09736632,"width":0.5668218,"height":0.90263367},"on_screen":true,"value":"[2026-05-28 08:28:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"73199e23-a066-42ba-b189-2802e0869a44\",\"trace_id\":\"e53672c2-0f50-409d-af25-84ab485c505d\"}\n[2026-05-28 08:28:04] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"73199e23-a066-42ba-b189-2802e0869a44\",\"trace_id\":\"e53672c2-0f50-409d-af25-84ab485c505d\"}\n[2026-05-28 08:28:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"73199e23-a066-42ba-b189-2802e0869a44\",\"trace_id\":\"e53672c2-0f50-409d-af25-84ab485c505d\"}\n[2026-05-28 08:28:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"741b2c4e-6a44-4c46-b9fb-fce017aef225\",\"trace_id\":\"804dc547-eb25-4b32-8d0f-c87019773085\"}\n[2026-05-28 08:28:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"741b2c4e-6a44-4c46-b9fb-fce017aef225\",\"trace_id\":\"804dc547-eb25-4b32-8d0f-c87019773085\"}\n[2026-05-28 08:28:09] local.NOTICE: Monitoring start {\"correlation_id\":\"8ae5c131-edd9-463d-8161-875f4d34320f\",\"trace_id\":\"1b6420c8-ef4e-4566-81b2-688696064648\"}\n[2026-05-28 08:28:09] local.NOTICE: Monitoring end {\"correlation_id\":\"8ae5c131-edd9-463d-8161-875f4d34320f\",\"trace_id\":\"1b6420c8-ef4e-4566-81b2-688696064648\"}\n[2026-05-28 08:28:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"6f5390d3-abe7-4e56-a662-aeed1098941b\",\"trace_id\":\"b57dc2df-2f4d-4d3b-b09a-aa6e61205d5e\"}\n[2026-05-28 08:28:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"6f5390d3-abe7-4e56-a662-aeed1098941b\",\"trace_id\":\"b57dc2df-2f4d-4d3b-b09a-aa6e61205d5e\"}\n[2026-05-28 08:28:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"ba694158-ea28-4ac1-b134-83ac485146e0\",\"trace_id\":\"83a26b74-baa5-407e-9fc2-2b49d65b1c77\"}\n[2026-05-28 08:28:12] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"ba694158-ea28-4ac1-b134-83ac485146e0\",\"trace_id\":\"83a26b74-baa5-407e-9fc2-2b49d65b1c77\"}\n[2026-05-28 08:28:12] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"ba694158-ea28-4ac1-b134-83ac485146e0\",\"trace_id\":\"83a26b74-baa5-407e-9fc2-2b49d65b1c77\"}\n[2026-05-28 08:28:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"ba694158-ea28-4ac1-b134-83ac485146e0\",\"trace_id\":\"83a26b74-baa5-407e-9fc2-2b49d65b1c77\"}\n[2026-05-28 08:28:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"b79833c7-3eab-4eb7-98bb-42359039b8fb\",\"trace_id\":\"a8e159bc-867d-40af-bf7d-1228cf6d4f16\"}\n[2026-05-28 08:28:14] local.INFO: Running conference:monitor:count command for activities in (2026-05-28 08:26:00, 2026-05-28 08:28:00] {\"correlation_id\":\"b79833c7-3eab-4eb7-98bb-42359039b8fb\",\"trace_id\":\"a8e159bc-867d-40af-bf7d-1228cf6d4f16\"}\n[2026-05-28 08:28:14] local.INFO: [conference:monitor:count] No activities found in (2026-05-28 08:26:00, 2026-05-28 08:28:00] {\"correlation_id\":\"b79833c7-3eab-4eb7-98bb-42359039b8fb\",\"trace_id\":\"a8e159bc-867d-40af-bf7d-1228cf6d4f16\"}\n[2026-05-28 08:28:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"b79833c7-3eab-4eb7-98bb-42359039b8fb\",\"trace_id\":\"a8e159bc-867d-40af-bf7d-1228cf6d4f16\"}\n[2026-05-28 08:28:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"d51071d5-ead0-45f0-a07e-e3234074f884\",\"trace_id\":\"77173d9f-596f-405f-ae55-ba117b66455d\"}\n[2026-05-28 08:28:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"calendar:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.NOTICE: Calendar sync start {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"d51071d5-ead0-45f0-a07e-e3234074f884\",\"trace_id\":\"77173d9f-596f-405f-ae55-ba117b66455d\"}\n[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1393,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1393,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1393,\"provider\":\"google\",\"refreshToken\":\"5aa7e2d96b53201cd16fca5d2e4ef3ad03320971fc064781d18aee3ae7b99fbf\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1393,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1393,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1387,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1387,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1387,\"provider\":\"google\",\"refreshToken\":\"8157ac6de94842937194009e9c50e459253600f799dacf6a40755ffdbeb5bba6\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1387,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1387,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1348,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1348,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1348,\"provider\":\"google\",\"refreshToken\":\"9e7d13d3032d0cb1b79d8e95aef01383e8e91eb52ff8ee960c8a0b6b95cd8c73\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1348,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1348,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1361,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1361,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1361,\"provider\":\"google\",\"refreshToken\":\"6c843da199c2b9907445329304fcc4ec5057a4ee748d8299641764395c08e1fd\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1361,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1361,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1310,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1310,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1310,\"provider\":\"google\",\"refreshToken\":\"e34818922c2830a660813a63f6169a4a9a992ae2cccd7dc8dd7796cfdb470ef1\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1310,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1310,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1333,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1333,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1333,\"provider\":\"google\",\"refreshToken\":\"6c902986546d8e8da1dc539b046cdc1d458f519acc972e5b5f1d6a1a295165e0\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1333,\"provider\":\"google\",\"responseBody\":{\"error\":\"unauthorized_client\",\"error_description\":\"Unauthorized\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1333,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1368,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1368,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1368,\"provider\":\"google\",\"refreshToken\":\"d2f128898ff8543bd16b69cfae37896ab85119b0f5ed2b431d739593bb600333\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1368,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1368,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1365,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1365,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1365,\"provider\":\"google\",\"refreshToken\":\"7676e4a9afcd082b413248ab5ec6e487021fec6a9bdf315860a59cefad9caad8\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1365,\"provider\":\"google\",\"responseBody\":{\"error\":\"unauthorized_client\",\"error_description\":\"Unauthorized\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1365,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1364,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1364,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1364,\"provider\":\"google\",\"refreshToken\":\"dd5882ebce76e645292ce33ae74238abbb77c0a4ecc6a2bfe723cad82e72ba8e\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1364,\"provider\":\"google\",\"responseBody\":{\"error\":\"unauthorized_client\",\"error_description\":\"Unauthorized\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1364,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1370,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1370,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1370,\"provider\":\"office\",\"refreshToken\":\"b7ee8035306d0043cea6e00e7c4fe14f745e44074a1194db62a31cdf8b70af3e\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1370,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 41d8db5c-a91f-41a6-9b5c-22a6c99b9100 Correlation ID: 70bc0a6f-1565-4e74-94dc-419d94108fa9 Timestamp: 2026-05-28 08:28:18Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:18Z\\\",\\\"trace_id\\\":\\\"41d8db5c-a91f-41a6-9b5c-22a6c99b9100\\\",\\\"correlation_id\\\":\\\"70bc0a6f-1565-4e74-94dc-419d94108fa9\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1370,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1202,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1202,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1202,\"provider\":\"office\",\"refreshToken\":\"b458799ccc29b21a6e2eb5260fdb63e49ccba21bf942a3973fb63799bd7f0afe\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1202,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: d3d14dfc-1b70-40c4-b9db-fab12f748300 Correlation ID: 4c5f746c-8366-44c1-8733-6877607826db Timestamp: 2026-05-28 08:28:19Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:19Z\\\",\\\"trace_id\\\":\\\"d3d14dfc-1b70-40c4-b9db-fab12f748300\\\",\\\"correlation_id\\\":\\\"4c5f746c-8366-44c1-8733-6877607826db\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1202,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: Calendar sync job dispatched {\"calendar_id\":501} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1300,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1300,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1300,\"provider\":\"google\",\"refreshToken\":\"4b811db0725fd9602a95943519a7da935e2a5065da7d9ebfcb170752e3e1ddb8\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1300,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1300,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1409,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1409,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1409,\"provider\":\"google\",\"refreshToken\":\"e2a3f2d06894894eed1ee87d9db1ace77d4d42ee6e1288a8940ad2c10333b0c4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1409,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1409,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1352,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1352,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1352,\"provider\":\"google\",\"refreshToken\":\"dd4b16b00fdc1216da6b717c02338c073636e29162826b2de6db3f064fc029eb\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1352,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1352,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1296,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1296,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1296,\"provider\":\"office\",\"refreshToken\":\"011ae723c9d800c674e0b4be76f49fc046dac7d501b66c59ef0d9549cfa56ae5\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [Calendar] Processing sync {\"calendarId\":\"a33076c1-8d97-431a-99f0-85c9524e118b\",\"from\":null,\"to\":null,\"delta\":\"CIiFh8TP44kDEIiFh8TP44kDGAUgkZvkzgIokZvkzgI=\",\"last_sync\":\"2024-12-09 07:12:53\",\"dateMode\":\"daily\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"integration-app\",\"crm_owner\":1695,\"team_id\":3143} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1296,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: dd83a147-95bc-407c-8c9b-3c14e7cb7d00 Correlation ID: bb16bae3-b3c4-467e-bd95-4e7ab85364c9 Timestamp: 2026-05-28 08:28:20Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:20Z\\\",\\\"trace_id\\\":\\\"dd83a147-95bc-407c-8c9b-3c14e7cb7d00\\\",\\\"correlation_id\\\":\\\"bb16bae3-b3c4-467e-bd95-4e7ab85364c9\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1296,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":391,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":391,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":391,\"provider\":\"office\",\"refreshToken\":\"00045eebae0f39b34887c6d53f92ae78064f7145e1f4b67754aebd03cfb2d881\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [Google Calendar] Failed to watch channel for calendar {\"calendarId\":\"a33076c1-8d97-431a-99f0-85c9524e118b\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.WARNING: [Calendar] Sync failed {\"calendarId\":\"a33076c1-8d97-431a-99f0-85c9524e118b\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":391,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 587224ad-f597-4371-b2ba-00fcd2da1b00 Correlation ID: 4e752610-95b1-4606-847f-68e00f90be0a Timestamp: 2026-05-28 08:28:21Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:21Z\\\",\\\"trace_id\\\":\\\"587224ad-f597-4371-b2ba-00fcd2da1b00\\\",\\\"correlation_id\\\":\\\"4e752610-95b1-4606-847f-68e00f90be0a\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":391,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1271,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1271,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1271,\"provider\":\"office\",\"refreshToken\":\"118cde2c06993147b07ccaec4cbcd5026a819dea6c71081166a492933e392afb\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1271,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: dd8bf2a7-bc49-43d7-a487-892c51e27600 Correlation ID: 51e3eb6c-c47e-4dd7-91aa-e734fe5b65cf Timestamp: 2026-05-28 08:28:21Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:21Z\\\",\\\"trace_id\\\":\\\"dd8bf2a7-bc49-43d7-a487-892c51e27600\\\",\\\"correlation_id\\\":\\\"51e3eb6c-c47e-4dd7-91aa-e734fe5b65cf\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1271,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1351,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1351,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1351,\"provider\":\"google\",\"refreshToken\":\"4271d15b9e60a606439caddc68337f783e472c85b03dacff14d1b6dfded9051c\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1351,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1351,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1366,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1366,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1366,\"provider\":\"google\",\"refreshToken\":\"ae21385059b2eebfd43f68aecd56eccd702a1aabb6598f1f7ab594ed8af491b4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1366,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1366,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: Calendar sync job dispatched {\"calendar_id\":378} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: Calendar sync job dispatched {\"calendar_id\":504} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.NOTICE: Calendar sync end {\"retrieved_calendars\":31,\"processed_calendars\":3} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"calendar:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [Calendar] Processing sync {\"calendarId\":\"2676cb6d-f86c-427e-bf78-591e388e3c1e\",\"from\":null,\"to\":null,\"delta\":\"CJ_x49O3jpIDEJ_x49O3jpIDGAUgw67KlwMow67KlwM=\",\"last_sync\":\"2026-01-19 07:48:40\",\"dateMode\":\"daily\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.WARNING: [Pipedrive] Account not connected for user {\"userId\":\"e6538737-e7b4-455f-a37a-3e79b665a220\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":1116,\"sociable_id\":241,\"provider_user_id\":\"19555731\",\"expires\":1779091997,\"refresh_token_expires\":null,\"provider\":\"pipedrive\",\"state\":\"full-refresh\",\"auth_scope\":\"base,deals:full,activities:full,contacts:full,search:read\",\"retry_after\":null,\"created_at\":\"2023-09-08 09:44:29\",\"updated_at\":\"2026-05-18 08:13:32\"}}} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"pipedrive\",\"crm_owner\":241,\"team_id\":19} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"pipedrive\",\"team_id\":19} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"pipedrive\",\"team_id\":19} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.WARNING: [Calendar] CRM disconnected for user so events will not be matched {\"provider\":\"pipedrive\",\"user_id\":241,\"message\":\"Your Pipedrive account has become disconnected. Please login to Jiminny to reconnect.\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [Google Calendar] Failed to watch channel for calendar {\"calendarId\":\"2676cb6d-f86c-427e-bf78-591e388e3c1e\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.WARNING: [Calendar] Sync failed {\"calendarId\":\"2676cb6d-f86c-427e-bf78-591e388e3c1e\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [Calendar] Processing sync {\"calendarId\":\"9e8b1a2c-1a8f-42bd-b161-810fc0baf540\",\"from\":null,\"to\":null,\"delta\":\"R0usmcdvmMuZCBYV0hguCBhf4uKqyU9_gdNd-le_nqqau95XAUmZwlIAy2uwtCf5sA67w6NIiDvawUSmVjpTzZO-RsxLdeS-g8Kxy6ODZQxAxafq8AJNx0hJV7T291NUvfaPYqLMv-3je3IdhAPUtXQXkHtYaBAlX_DDBxwc3zYoVVQ8iM9mQkBykdA3sh-KVYPyzi7nK4cZg5Jzpu9tHA.UA7urx3pJyhUhdo_16STIbSNXUrF-qeQVIis9stVUeY\",\"last_sync\":\"2026-05-28 07:44:06\",\"dateMode\":\"daily\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":89,\"team_id\":2} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [MS Office Calendar] Skipping delta sync for daily mode {\"calendarId\":\"9e8b1a2c-1a8f-42bd-b161-810fc0baf540\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:29:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"86a65904-a9f8-43c9-b0c3-1e9c8b4b9541\",\"trace_id\":\"800b02ff-3553-46a3-a8c6-c12324a1ce53\"}\n[2026-05-28 08:29:05] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"86a65904-a9f8-43c9-b0c3-1e9c8b4b9541\",\"trace_id\":\"800b02ff-3553-46a3-a8c6-c12324a1ce53\"}\n[2026-05-28 08:29:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"86a65904-a9f8-43c9-b0c3-1e9c8b4b9541\",\"trace_id\":\"800b02ff-3553-46a3-a8c6-c12324a1ce53\"}\n[2026-05-28 08:29:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"e5162656-5b49-4857-9917-f0cf3ddffe27\",\"trace_id\":\"a3a53cc5-596d-474c-b9c4-f6c5f7ebdfd0\"}\n[2026-05-28 08:29:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"e5162656-5b49-4857-9917-f0cf3ddffe27\",\"trace_id\":\"a3a53cc5-596d-474c-b9c4-f6c5f7ebdfd0\"}\n[2026-05-28 08:29:09] local.NOTICE: Monitoring start {\"correlation_id\":\"f559463e-0c12-46df-8b53-0c50cf4aa3eb\",\"trace_id\":\"5a09aee9-5f75-4bfa-93e4-df0ff76f2326\"}\n[2026-05-28 08:29:09] local.NOTICE: Monitoring end {\"correlation_id\":\"f559463e-0c12-46df-8b53-0c50cf4aa3eb\",\"trace_id\":\"5a09aee9-5f75-4bfa-93e4-df0ff76f2326\"}\n[2026-05-28 08:29:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"9b1cc2f1-0c8a-4aa0-a9e8-57ac879839e4\",\"trace_id\":\"d69dd133-b5f0-4568-81ef-9cce3d1c5c9e\"}\n[2026-05-28 08:29:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"9b1cc2f1-0c8a-4aa0-a9e8-57ac879839e4\",\"trace_id\":\"d69dd133-b5f0-4568-81ef-9cce3d1c5c9e\"}\n[2026-05-28 08:29:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"87e10603-9e6f-4d71-97ab-5ba67103e5fd\",\"trace_id\":\"0aae0afb-779f-4999-892d-0188e14b3dcb\"}\n[2026-05-28 08:29:12] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"87e10603-9e6f-4d71-97ab-5ba67103e5fd\",\"trace_id\":\"0aae0afb-779f-4999-892d-0188e14b3dcb\"}\n[2026-05-28 08:29:12] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"87e10603-9e6f-4d71-97ab-5ba67103e5fd\",\"trace_id\":\"0aae0afb-779f-4999-892d-0188e14b3dcb\"}\n[2026-05-28 08:29:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"87e10603-9e6f-4d71-97ab-5ba67103e5fd\",\"trace_id\":\"0aae0afb-779f-4999-892d-0188e14b3dcb\"}\n[2026-05-28 08:30:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"200b132b-d8db-4010-b968-fe5e3fcc42f1\",\"trace_id\":\"7457715a-3b9d-4c35-a499-455c83e925ab\"}\n[2026-05-28 08:30:04] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"200b132b-d8db-4010-b968-fe5e3fcc42f1\",\"trace_id\":\"7457715a-3b9d-4c35-a499-455c83e925ab\"}\n[2026-05-28 08:30:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"200b132b-d8db-4010-b968-fe5e3fcc42f1\",\"trace_id\":\"7457715a-3b9d-4c35-a499-455c83e925ab\"}\n[2026-05-28 08:30:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"a94ef973-dee7-4bdf-99aa-9ff06f5a5561\",\"trace_id\":\"4e37013f-2993-4c71-87d9-560f8f429d27\"}\n[2026-05-28 08:30:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"a94ef973-dee7-4bdf-99aa-9ff06f5a5561\",\"trace_id\":\"4e37013f-2993-4c71-87d9-560f8f429d27\"}\n[2026-05-28 08:30:07] local.NOTICE: Monitoring start {\"correlation_id\":\"691e7103-784d-4b4a-8036-f3c624a186db\",\"trace_id\":\"991dd947-ed80-4080-8769-8ee7efc4e6a4\"}\n[2026-05-28 08:30:07] local.NOTICE: Monitoring end {\"correlation_id\":\"691e7103-784d-4b4a-8036-f3c624a186db\",\"trace_id\":\"991dd947-ed80-4080-8769-8ee7efc4e6a4\"}\n[2026-05-28 08:30:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"00cf8914-d440-4826-a079-ee4586e76c62\",\"trace_id\":\"d77009ee-8d7b-44ae-bb21-2080b6d48c6c\"}\n[2026-05-28 08:30:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"00cf8914-d440-4826-a079-ee4586e76c62\",\"trace_id\":\"d77009ee-8d7b-44ae-bb21-2080b6d48c6c\"}\n[2026-05-28 08:30:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"7c9550d0-42ed-4b1d-b5b3-7dca67f743ec\",\"trace_id\":\"84177853-9530-4b1e-bde6-3dc0c71883ee\"}\n[2026-05-28 08:30:10] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"7c9550d0-42ed-4b1d-b5b3-7dca67f743ec\",\"trace_id\":\"84177853-9530-4b1e-bde6-3dc0c71883ee\"}\n[2026-05-28 08:30:10] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"7c9550d0-42ed-4b1d-b5b3-7dca67f743ec\",\"trace_id\":\"84177853-9530-4b1e-bde6-3dc0c71883ee\"}\n[2026-05-28 08:30:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"7c9550d0-42ed-4b1d-b5b3-7dca67f743ec\",\"trace_id\":\"84177853-9530-4b1e-bde6-3dc0c71883ee\"}\n[2026-05-28 08:30:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"85cc6c92-262b-45c5-bbcc-4a084137fde3\",\"trace_id\":\"058bc9a3-67af-49b6-a87c-8a0a0bc0c47a\"}\n[2026-05-28 08:30:12] local.INFO: Running conference:monitor:count command for activities in (2026-05-28 08:28:00, 2026-05-28 08:30:00] {\"correlation_id\":\"85cc6c92-262b-45c5-bbcc-4a084137fde3\",\"trace_id\":\"058bc9a3-67af-49b6-a87c-8a0a0bc0c47a\"}\n[2026-05-28 08:30:12] local.INFO: [conference:monitor:count] No activities found in (2026-05-28 08:28:00, 2026-05-28 08:30:00] {\"correlation_id\":\"85cc6c92-262b-45c5-bbcc-4a084137fde3\",\"trace_id\":\"058bc9a3-67af-49b6-a87c-8a0a0bc0c47a\"}\n[2026-05-28 08:30:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"85cc6c92-262b-45c5-bbcc-4a084137fde3\",\"trace_id\":\"058bc9a3-67af-49b6-a87c-8a0a0bc0c47a\"}\n[2026-05-28 08:30:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"5083d024-d669-4c6a-bde3-ce084d6a628c\",\"trace_id\":\"83110e1f-4309-4f4a-b8bb-eab5c0ec081e\"}\n[2026-05-28 08:30:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"5083d024-d669-4c6a-bde3-ce084d6a628c\",\"trace_id\":\"83110e1f-4309-4f4a-b8bb-eab5c0ec081e\"}\n[2026-05-28 08:30:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"bc529b16-9502-4df3-b2c0-c63fcf977ed5\",\"trace_id\":\"9dd5d6d0-4cc5-454c-a0c8-0e72b69eeb29\"}\n[2026-05-28 08:30:15] local.INFO: [TextRelayService] Starting sync {\"mailbox\":\"catch-all@txt.staging.jiminny.com\",\"expected_alias\":\"catch-all\",\"expected_host\":\"txt.staging.jiminny.com\"} {\"correlation_id\":\"bc529b16-9502-4df3-b2c0-c63fcf977ed5\",\"trace_id\":\"9dd5d6d0-4cc5-454c-a0c8-0e72b69eeb29\"}\n[2026-05-28 08:30:15] local.INFO: [TextRelayService] Sync completed {\"mailbox\":\"catch-all@txt.staging.jiminny.com\",\"messages_processed\":0,\"message_ids\":[]} {\"correlation_id\":\"bc529b16-9502-4df3-b2c0-c63fcf977ed5\",\"trace_id\":\"9dd5d6d0-4cc5-454c-a0c8-0e72b69eeb29\"}\n[2026-05-28 08:30:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"bc529b16-9502-4df3-b2c0-c63fcf977ed5\",\"trace_id\":\"9dd5d6d0-4cc5-454c-a0c8-0e72b69eeb29\"}\n[2026-05-28 08:30:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"b655bca8-effa-420b-8686-95ba96f27085\",\"trace_id\":\"b1f43a19-c7ad-428e-9933-4e509b5f0055\"}\n[2026-05-28 08:30:18] local.INFO: Running pre-meeting notification command {\"correlation_id\":\"b655bca8-effa-420b-8686-95ba96f27085\",\"trace_id\":\"b1f43a19-c7ad-428e-9933-4e509b5f0055\"}\n[2026-05-28 08:30:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"b655bca8-effa-420b-8686-95ba96f27085\",\"trace_id\":\"b1f43a19-c7ad-428e-9933-4e509b5f0055\"}\n[2026-05-28 08:30:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"5a8493c4-3ef7-4453-98b7-f32225d453fe\",\"trace_id\":\"056f1aea-8825-4e2c-8239-7804086e504e\"}\n[2026-05-28 08:30:20] local.INFO: Running conference:monitor:start command for activities in (2026-05-28 08:20:00, 2026-05-28 08:25:00] {\"correlation_id\":\"5a8493c4-3ef7-4453-98b7-f32225d453fe\",\"trace_id\":\"056f1aea-8825-4e2c-8239-7804086e504e\"}\n[2026-05-28 08:30:20] local.INFO: [conference:monitor:start] No activities found in (2026-05-28 08:20:00, 2026-05-28 08:25:00] {\"correlation_id\":\"5a8493c4-3ef7-4453-98b7-f32225d453fe\",\"trace_id\":\"056f1aea-8825-4e2c-8239-7804086e504e\"}\n[2026-05-28 08:30:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"5a8493c4-3ef7-4453-98b7-f32225d453fe\",\"trace_id\":\"056f1aea-8825-4e2c-8239-7804086e504e\"}\n[2026-05-28 08:30:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"18a2aed9-1aae-4b10-a7fa-f75a147db499\",\"trace_id\":\"fff0c9b2-1c60-4402-b30a-2f41d9b45db3\"}\n[2026-05-28 08:30:22] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesEnded {\"from\":\"08:25\",\"to\":\"08:30\"} {\"correlation_id\":\"18a2aed9-1aae-4b10-a7fa-f75a147db499\",\"trace_id\":\"fff0c9b2-1c60-4402-b30a-2f41d9b45db3\"}\n[2026-05-28 08:30:22] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesWithUnfinishedSession {\"from\":\"22:20\",\"to\":\"22:25\"} {\"correlation_id\":\"18a2aed9-1aae-4b10-a7fa-f75a147db499\",\"trace_id\":\"fff0c9b2-1c60-4402-b30a-2f41d9b45db3\"}\n[2026-05-28 08:30:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"18a2aed9-1aae-4b10-a7fa-f75a147db499\",\"trace_id\":\"fff0c9b2-1c60-4402-b30a-2f41d9b45db3\"}\n[2026-05-28 08:30:23] local.NOTICE: Repairing HubSpot tokens start {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:23] local.INFO: Trying to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:23] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:23] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":59,\"provider\":\"hubspot\",\"refreshToken\":\"97b78f6e2cc49965c00c2492b602b02708b1392551e6b3f113fbaa48992af90b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:26] local.ERROR: Failed to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:26] local.INFO: Trying to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:26] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:26] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":306,\"provider\":\"hubspot\",\"refreshToken\":\"6fa6aa8cc641d131231acc3470f5c03cb3b07b2e580fb18f8acb3b1dbb72549b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.ERROR: Failed to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.INFO: Trying to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1372,\"provider\":\"hubspot\",\"refreshToken\":\"9aa73948c761da29dce46c177cf9aee1fde483a44169ca38723f9f0597d7a8c4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.ERROR: Failed to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.NOTICE: Repairing HubSpot tokens end {\"total\":3,\"fixed\":0,\"failed\":3} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"jiminny:transcription:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"f73071c7-8696-459f-8aff-e61a7c6b30e6\",\"trace_id\":\"d72fc2ce-5064-4877-b401-10891378e1bc\"}\n[2026-05-28 08:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"720d5c87-3d13-4193-87c9-efb8dc6df7c8\",\"trace_id\":\"a9d9c9fe-db29-44a1-a5f6-1905d48dde90\"}\n[2026-05-28 08:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"jiminny:transcription:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"f73071c7-8696-459f-8aff-e61a7c6b30e6\",\"trace_id\":\"d72fc2ce-5064-4877-b401-10891378e1bc\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Command] Starting polling service {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] Service starting {\"memory_limit\":\"256M\",\"max_execution_time\":\"0\",\"initial_memory_mb\":62.0} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] Acquired polling lock {\"expires_at\":\"2026-05-28T08:32:33.444809Z\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"720d5c87-3d13-4193-87c9-efb8dc6df7c8\",\"trace_id\":\"a9d9c9fe-db29-44a1-a5f6-1905d48dde90\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:35] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:reset-governor\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"c692a62b-3b1a-4ff3-b965-388a7d12f619\",\"trace_id\":\"d1bdfdec-73bd-499f-a31e-b25a864da976\"}\n[2026-05-28 08:30:35] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:reset-governor\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"c692a62b-3b1a-4ff3-b965-388a7d12f619\",\"trace_id\":\"d1bdfdec-73bd-499f-a31e-b25a864da976\"}\n[2026-05-28 08:30:38] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:38] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:38] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:39] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814238,\"provider\":\"twilio-flex\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814239,\"provider\":\"xant\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814240,\"provider\":\"apollo\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814241,\"provider\":\"groove\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814242,\"provider\":\"twilio-video\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814243,\"provider\":\"hubspot\",\"team\":\"hubspot\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:fail-stalled\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"f6d797df-5275-4cf1-8ddd-300c125df8da\",\"trace_id\":\"2b46c31f-aced-4324-a70a-6395f0a72618\"}\n[2026-05-28 08:30:42] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:fail-stalled\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"f6d797df-5275-4cf1-8ddd-300c125df8da\",\"trace_id\":\"2b46c31f-aced-4324-a70a-6395f0a72618\"}\n[2026-05-28 08:30:42] local.WARNING: [Salesforce] Account not connected for user {\"userId\":\"cdf8b554-d951-4758-bc2b-c1b85d1cd0b9\",\"account\":null} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"salesforce\",\"crm_owner\":3,\"team_id\":1} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [CrmOwnerResolver] TeamMember found with active crm connection {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1194,\"provider\":\"twilio-flex\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1194,\"provider\":\"twilio-flex\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SyncActivity] Start {\"import_id\":814238,\"provider\":\"twilio-flex\",\"provider_id\":317,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.NOTICE: [TwilioFlex] Calls import start {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.ALERT: [SyncActivity] Failed {\"import_id\":814238,\"provider\":\"twilio-flex\",\"provider_id\":317,\"team\":\"jiminny\",\"team_id\":1,\"reason\":\"[HTTP 401] Unable to fetch page: Authenticate\",\"file\":\"/home/jiminny/vendor/twilio/sdk/src/Twilio/Page.php\",\"line\":60} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SyncActivity] Start {\"import_id\":814239,\"provider\":\"xant\",\"provider_id\":161,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [Salesforce] Performing query {\"query\":\"\n SELECT Playbooks_Call_Date__c,Playbooks_Call_Recording__c,CreatedDate,TaskSubtype,CallType,CallDurationInSeconds,Id,OwnerId,WhoId,WhatId,Priority,ActivityDate,Subject,Description,Status,Type\n FROM Task\n WHERE IsDeleted = false\n AND LastModifiedDate >= :from\n AND LastModifiedDate <= :to\n ORDER BY LastModifiedDate ASC\n LIMIT :limit\",\"params\":{\"from\":\"2026-05-28T08:14:00Z\",\"to\":\"2026-05-28T08:30:00Z\",\"ownerId\":null,\"subType\":null,\"limit\":5000}} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [Salesforce] Sending request {\"endpoint\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=%0A++++++++++++SELECT+Playbooks_Call_Date__c%2CPlaybooks_Call_Recording__c%2CCreatedDate%2CTaskSubtype%2CCallType%2CCallDurationInSeconds%2CId%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%0A++++++++++++++FROM+Task%0A+++++++++++++WHERE+IsDeleted+%3D+false%0A+++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A+++++++++++++++AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z%0A++++++++++ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000 GET\",\"team_id\":1} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:44] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:44] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:44] local.INFO: [Xant (InsideSales)] No calls found. {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] End {\"import_id\":814239,\"provider\":\"xant\",\"provider_id\":161,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Memory usage {\"import_id\":814239,\"provider\":\"xant\",\"provider_id\":161,\"team\":\"jiminny\",\"team_id\":1,\"memory_usage\":24080216,\"memory_real_usage\":65011712,\"pid\":21708} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Start {\"import_id\":814240,\"provider\":\"apollo\",\"provider_id\":441,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Performing query {\"query\":\"\n SELECT AccountId,CreatedDate,TaskSubtype,CallType,Id,OwnerId,WhoId,WhatId,Priority,ActivityDate,Subject,Description,Status,Type\n FROM Task\n WHERE IsDeleted = false\n AND LastModifiedDate >= :from\n AND LastModifiedDate <= :to\n ORDER BY LastModifiedDate ASC\n LIMIT :limit\",\"params\":{\"from\":\"2026-05-28T08:14:00Z\",\"to\":\"2026-05-28T08:30:00Z\",\"ownerId\":null,\"subType\":null,\"limit\":5000}} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Sending request {\"endpoint\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=%0A++++++++++++SELECT+AccountId%2CCreatedDate%2CTaskSubtype%2CCallType%2CId%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%0A++++++++++++++FROM+Task%0A+++++++++++++WHERE+IsDeleted+%3D+false%0A+++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A+++++++++++++++AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z%0A++++++++++ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000 GET\",\"team_id\":1} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Apollo] No calls found. {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] End {\"import_id\":814240,\"provider\":\"apollo\",\"provider_id\":441,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Memory usage {\"import_id\":814240,\"provider\":\"apollo\",\"provider_id\":441,\"team\":\"jiminny\",\"team_id\":1,\"memory_usage\":24242184,\"memory_real_usage\":65011712,\"pid\":21708} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Start {\"import_id\":814241,\"provider\":\"groove\",\"provider_id\":228,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Performing query {\"query\":\"\n SELECT call_recording_url__c,TaskSubtype,CreatedDate,CallType,CallDurationInSeconds,Id,OwnerId,WhoId,WhatId,Priority,ActivityDate,Subject,Description,Status,Type\n FROM Task\n WHERE IsDeleted = false\n AND LastModifiedDate >= :from\n AND LastModifiedDate <= :to\n ORDER BY LastModifiedDate ASC\n LIMIT :limit\",\"params\":{\"from\":\"2026-05-28T08:14:00Z\",\"to\":\"2026-05-28T08:30:00Z\",\"ownerId\":null,\"subType\":null,\"limit\":5000}} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Sending request {\"endpoint\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=%0A++++++++++++SELECT+call_recording_url__c%2CTaskSubtype%2CCreatedDate%2CCallType%2CCallDurationInSeconds%2CId%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%0A++++++++++++++FROM+Task%0A+++++++++++++WHERE+IsDeleted+%3D+false%0A+++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A+++++++++++++++AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z%0A++++++++++ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000 GET\",\"team_id\":1} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"b2b37795-cfa8-472a-b681-322ce27c0e08\",\"trace_id\":\"605e54f2-d4f9-4683-b3fd-6c1c23e691b7\"}\n[2026-05-28 08:30:44] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"b2b37795-cfa8-472a-b681-322ce27c0e08\",\"trace_id\":\"605e54f2-d4f9-4683-b3fd-6c1c23e691b7\"}\n[2026-05-28 08:30:44] local.ERROR: [Salesforce] Request exception [400] \nSELECT call_recording_url__c,TaskSubtype\n ^\nERROR at Row:1:Column:8\nNo such column 'call_recording_url__c' on entity 'Task'. If you are attempting to use a custom field, be sure to append the '__c' after the custom field name. Please reference your WSDL or the describe call for the appropriate names. {\"url\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=%0A++++++++++++SELECT+call_recording_url__c%2CTaskSubtype%2CCreatedDate%2CCallType%2CCallDurationInSeconds%2CId%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%0A++++++++++++++FROM+Task%0A+++++++++++++WHERE+IsDeleted+%3D+false%0A+++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A+++++++++++++++AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z%0A++++++++++ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000\",\"data\":{\"headers\":{\"Authorization\":\"Bearer 00D2g0000008hH4!AQEAQHWUK6nshi8dSCX9CJphxkVivcv_TK98TLOckVy4i0Z1gQfAoRRuH2LVwDXDkbTPs80wvQjczjAlOz0UEtbHoORBLi2u\"}},\"response\":{\"GuzzleHttp\\\\Psr7\\\\Stream\":\"[{\\\"message\\\":\\\"\\\\nSELECT call_recording_url__c,TaskSubtype\\\\n ^\\\\nERROR at Row:1:Column:8\\\\nNo such column 'call_recording_url__c' on entity 'Task'. If you are attempting to use a custom field, be sure to append the '__c' after the custom field name. Please reference your WSDL or the describe call for the appropriate names.\\\",\\\"errorCode\\\":\\\"INVALID_FIELD\\\"}]\"},\"fields\":[]} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.ALERT: [SyncActivity] Failed {\"import_id\":814241,\"provider\":\"groove\",\"provider_id\":228,\"team\":\"jiminny\",\"team_id\":1,\"reason\":\"\nSELECT call_recording_url__c,TaskSubtype\n ^\nERROR at Row:1:Column:8\nNo such column 'call_recording_url__c' on entity 'Task'. If you are attempting to use a custom field, be sure to append the '__c' after the custom field name. Please reference your WSDL or the describe call for the appropriate names.\",\"file\":\"/home/jiminny/app/Services/Crm/Salesforce/Client.php\",\"line\":564} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Start {\"import_id\":814242,\"provider\":\"twilio-video\",\"provider_id\":243,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Performing query {\"query\":\"SELECT Id,OwnerId,WhoId,WhatId,Priority,ActivityDate,Subject,Description,Status,Type,twilio_call_sid__c,Lead_UUID__c,Opportunity__c\n FROM Task\n WHERE Type = 'Video'\n AND isClosed = true\n AND IsDeleted = false\n AND LastModifiedDate >= :from\n AND twilio_call_sid__c != NULL AND LastModifiedDate <= :to ORDER BY LastModifiedDate ASC\n LIMIT :limit\",\"params\":{\"from\":\"2026-05-28T08:14:00Z\",\"to\":\"2026-05-28T08:30:00Z\",\"ownerId\":null,\"subType\":null,\"limit\":5000}} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Sending request {\"endpoint\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=SELECT+Id%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%2Ctwilio_call_sid__c%2CLead_UUID__c%2COpportunity__c%0A++++++++++++++FROM+Task%0A++++++++++++WHERE+Type+%3D+%27Video%27%0A++++++++++++++AND+isClosed+%3D+true%0A++++++++++++++AND+IsDeleted+%3D+false%0A++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A++++++++++++++AND+twilio_call_sid__c+%21%3D+NULL+AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z+ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000 GET\",\"team_id\":1} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [Twilio Video] No calls found. {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] End {\"import_id\":814242,\"provider\":\"twilio-video\",\"provider_id\":243,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] Memory usage {\"import_id\":814242,\"provider\":\"twilio-video\",\"provider_id\":243,\"team\":\"jiminny\",\"team_id\":1,\"memory_usage\":24634032,\"memory_real_usage\":65011712,\"pid\":21708} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":89,\"team_id\":2} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":408,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":408,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] Start {\"import_id\":814243,\"provider\":\"hubspot\",\"provider_id\":31,\"team\":\"hubspot\",\"team_id\":2} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [HubSpot] Search calls for period {\"from\":\"2026-05-28 08:14:00\",\"to\":\"2026-05-28 08:30:00\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] End {\"import_id\":814243,\"provider\":\"hubspot\",\"provider_id\":31,\"team\":\"hubspot\",\"team_id\":2} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] Memory usage {\"import_id\":814243,\"provider\":\"hubspot\",\"provider_id\":31,\"team\":\"hubspot\",\"team_id\":2,\"memory_usage\":24947696,\"memory_real_usage\":65011712,\"pid\":21708} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:46] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"nudges:send\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"f3e257b6-82bb-440c-bf76-855ac528e4e8\",\"trace_id\":\"f8a31218-7290-45ac-8fe1-ffb1b8527521\"}\n[2026-05-28 08:30:46] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"nudges:send\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"f3e257b6-82bb-440c-bf76-855ac528e4e8\",\"trace_id\":\"f8a31218-7290-45ac-8fe1-ffb1b8527521\"}\n[2026-05-28 08:30:50] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"jiminny:playlists:normalize-sort\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"a64b1836-79a1-41da-a4b0-bc0a9703a94b\",\"trace_id\":\"c53faedc-a7a7-41b7-8e51-e84dc2755d79\"}\n[2026-05-28 08:30:50] local.INFO: [Jiminny\\Component\\Playlist\\Command\\NormalizeSortCommand::handle] starting. {\"playlists\":[]} {\"correlation_id\":\"a64b1836-79a1-41da-a4b0-bc0a9703a94b\",\"trace_id\":\"c53faedc-a7a7-41b7-8e51-e84dc2755d79\"}\n[2026-05-28 08:30:50] local.INFO: [Jiminny\\Component\\Playlist\\Command\\NormalizeSortCommand::handle] finished. {\"normalizedPlaylists\":[],\"deletedPlaylists\":[]} {\"correlation_id\":\"a64b1836-79a1-41da-a4b0-bc0a9703a94b\",\"trace_id\":\"c53faedc-a7a7-41b7-8e51-e84dc2755d79\"}\n[2026-05-28 08:30:50] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"jiminny:playlists:normalize-sort\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"a64b1836-79a1-41da-a4b0-bc0a9703a94b\",\"trace_id\":\"c53faedc-a7a7-41b7-8e51-e84dc2755d79\"}\n[2026-05-28 08:30:59] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:59] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:59] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"41db30ba-33c5-46f1-b8bd-5d9e86a70d12\",\"trace_id\":\"a5e2028d-ca41-4ba1-9ddd-a246f83ef4cc\"}\n[2026-05-28 08:31:07] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"41db30ba-33c5-46f1-b8bd-5d9e86a70d12\",\"trace_id\":\"a5e2028d-ca41-4ba1-9ddd-a246f83ef4cc\"}\n[2026-05-28 08:31:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"41db30ba-33c5-46f1-b8bd-5d9e86a70d12\",\"trace_id\":\"a5e2028d-ca41-4ba1-9ddd-a246f83ef4cc\"}\n[2026-05-28 08:31:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"f6ed0a05-caa1-4cb6-ae83-63f44ae4e0d6\",\"trace_id\":\"16cd898d-57a1-4b74-90d1-f9223bbd8d7a\"}\n[2026-05-28 08:31:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"f6ed0a05-caa1-4cb6-ae83-63f44ae4e0d6\",\"trace_id\":\"16cd898d-57a1-4b74-90d1-f9223bbd8d7a\"}\n[2026-05-28 08:31:15] local.NOTICE: Monitoring start {\"correlation_id\":\"cdf384ea-4f59-4411-8ebf-efc299e4a1c8\",\"trace_id\":\"b069d3c8-2f77-4698-bd53-97de373652e8\"}\n[2026-05-28 08:31:15] local.NOTICE: Monitoring end {\"correlation_id\":\"cdf384ea-4f59-4411-8ebf-efc299e4a1c8\",\"trace_id\":\"b069d3c8-2f77-4698-bd53-97de373652e8\"}\n[2026-05-28 08:31:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"940a264b-4aee-40a0-a527-e101ea555a38\",\"trace_id\":\"cd9169ad-4c1e-452d-b7cb-66005aae4dc8\"}\n[2026-05-28 08:31:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"940a264b-4aee-40a0-a527-e101ea555a38\",\"trace_id\":\"cd9169ad-4c1e-452d-b7cb-66005aae4dc8\"}\n[2026-05-28 08:31:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"b798f381-71f2-4c51-a135-f91f09330cfd\",\"trace_id\":\"b44ed325-23f7-4f8b-a447-4c8d0ee99d01\"}\n[2026-05-28 08:31:23] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"b798f381-71f2-4c51-a135-f91f09330cfd\",\"trace_id\":\"b44ed325-23f7-4f8b-a447-4c8d0ee99d01\"}\n[2026-05-28 08:31:24] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"b798f381-71f2-4c51-a135-f91f09330cfd\",\"trace_id\":\"b44ed325-23f7-4f8b-a447-4c8d0ee99d01\"}\n[2026-05-28 08:31:24] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"b798f381-71f2-4c51-a135-f91f09330cfd\",\"trace_id\":\"b44ed325-23f7-4f8b-a447-4c8d0ee99d01\"}\n[2026-05-28 08:31:27] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"2d631328-f2b9-44f3-83d3-613b7b9b9ddc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:27] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"2d631328-f2b9-44f3-83d3-613b7b9b9ddc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"usage\":22563136,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [HubSpot] Syncing opportunities using strategy: lastModified {\"team\":2} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.4,\"average_seconds_per_request\":0.4} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [HubSpot] Synced opportunities {\"team\":2,\"strategies\":\"lastModified\",\"sync_count\":0,\"total\":0,\"last_synced_id\":null,\"duration_ms\":432.6} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"provider\":\"hubspot\",\"status\":\"completed\",\"duration_ms\":543.02,\"usage\":22983640,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"usage\":22961848,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"2ac0447f-3c8c-4ce0-baeb-b63ddb76fa9b\",\"account\":null} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":130,\"team_id\":42} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":23.85,\"usage\":23024000,\"real_usage\":65011712,\"pid\":21703,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"usage\":22984760,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"33e34a7a-1c02-4f04-87ac-22c3a385e6e3\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":306,\"sociable_id\":109,\"provider_user_id\":\"11348452\",\"expires\":1701077403,\"refresh_token_expires\":null,\"provider\":\"hubspot\",\"state\":\"full-refresh\",\"auth_scope\":null,\"retry_after\":null,\"created_at\":\"2020-09-01 16:59:04\",\"updated_at\":\"2023-11-27 09:30:03\"}}} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":109,\"team_id\":29} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":14.98,\"usage\":23047624,\"real_usage\":65011712,\"pid\":21703,\"reason\":\"Your HubSpot account has become disconnected. Please login to Jiminny to reconnect.\"} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal Polling] Service ending {\"runtime_seconds\":56,\"total_cycles\":5,\"files_downloaded\":0,\"empty_files\":0,\"other_portal_skipped\":0,\"total_events\":0,\"events_per_file\":0,\"avg_api_ms\":192.1,\"avg_download_ms\":0.0,\"avg_transform_ms\":0.0,\"avg_process_ms\":0.0,\"peak_memory_mb\":99.88} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal Polling] Released polling lock {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"usage\":23005136,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"71e3aac5-fb66-47c5-a236-2d051ae3e319\",\"account\":null} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":256,\"team_id\":49} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":34.51,\"usage\":23021248,\"real_usage\":65011712,\"pid\":21703,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:32:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"35f98b1b-7b16-4e79-a420-7e9818097d24\",\"trace_id\":\"d66deb58-fa13-486f-a866-2cac402dc589\"}\n[2026-05-28 08:32:06] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"35f98b1b-7b16-4e79-a420-7e9818097d24\",\"trace_id\":\"d66deb58-fa13-486f-a866-2cac402dc589\"}\n[2026-05-28 08:32:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"35f98b1b-7b16-4e79-a420-7e9818097d24\",\"trace_id\":\"d66deb58-fa13-486f-a866-2cac402dc589\"}\n[2026-05-28 08:32:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"bc6784c1-c46f-4295-be09-87334f4baa39\",\"trace_id\":\"74b00236-4ed0-4464-8b07-99c328ab6461\"}\n[2026-05-28 08:32:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"bc6784c1-c46f-4295-be09-87334f4baa39\",\"trace_id\":\"74b00236-4ed0-4464-8b07-99c328ab6461\"}\n[2026-05-28 08:32:11] local.NOTICE: Monitoring start {\"correlation_id\":\"caf4d1dd-2a52-40f5-834a-f9148f642e83\",\"trace_id\":\"1312bdcc-7e8b-480a-a935-2433fb79dc70\"}\n[2026-05-28 08:32:11] local.NOTICE: Monitoring end {\"correlation_id\":\"caf4d1dd-2a52-40f5-834a-f9148f642e83\",\"trace_id\":\"1312bdcc-7e8b-480a-a935-2433fb79dc70\"}\n[2026-05-28 08:32:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"64d86889-1f0d-4f7d-a1ac-6f56e58e775e\",\"trace_id\":\"b184d66b-49f8-40ec-afbe-2e76e9c7d952\"}\n[2026-05-28 08:32:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"64d86889-1f0d-4f7d-a1ac-6f56e58e775e\",\"trace_id\":\"b184d66b-49f8-40ec-afbe-2e76e9c7d952\"}\n[2026-05-28 08:32:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"8e6dd4bc-4f44-4fb2-b2ba-9e2f385996ef\",\"trace_id\":\"7767e0ca-37a3-43a5-972e-ea9a1bedea2f\"}\n[2026-05-28 08:32:20] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"8e6dd4bc-4f44-4fb2-b2ba-9e2f385996ef\",\"trace_id\":\"7767e0ca-37a3-43a5-972e-ea9a1bedea2f\"}\n[2026-05-28 08:32:20] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"8e6dd4bc-4f44-4fb2-b2ba-9e2f385996ef\",\"trace_id\":\"7767e0ca-37a3-43a5-972e-ea9a1bedea2f\"}\n[2026-05-28 08:32:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"8e6dd4bc-4f44-4fb2-b2ba-9e2f385996ef\",\"trace_id\":\"7767e0ca-37a3-43a5-972e-ea9a1bedea2f\"}\n[2026-05-28 08:32:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"6750ab25-6dff-4e7b-9f6e-bc7d1fc4221a\",\"trace_id\":\"3db6ce9b-167d-4214-a32c-67c611aa2bbe\"}\n[2026-05-28 08:32:22] local.INFO: Running conference:monitor:count command for activities in (2026-05-28 08:30:00, 2026-05-28 08:32:00] {\"correlation_id\":\"6750ab25-6dff-4e7b-9f6e-bc7d1fc4221a\",\"trace_id\":\"3db6ce9b-167d-4214-a32c-67c611aa2bbe\"}\n[2026-05-28 08:32:22] local.INFO: [conference:monitor:count] No activities found in (2026-05-28 08:30:00, 2026-05-28 08:32:00] {\"correlation_id\":\"6750ab25-6dff-4e7b-9f6e-bc7d1fc4221a\",\"trace_id\":\"3db6ce9b-167d-4214-a32c-67c611aa2bbe\"}\n[2026-05-28 08:32:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"6750ab25-6dff-4e7b-9f6e-bc7d1fc4221a\",\"trace_id\":\"3db6ce9b-167d-4214-a32c-67c611aa2bbe\"}\n[2026-05-28 08:32:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"04510c2c-638c-4687-81d7-b12e76f41df3\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}\n[2026-05-28 08:32:23] local.INFO: [EmailSchedule] STARTING batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"04510c2c-638c-4687-81d7-b12e76f41df3\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}\n[2026-05-28 08:32:23] local.INFO: [EmailSchedule] FINISHED batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"04510c2c-638c-4687-81d7-b12e76f41df3\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}\n[2026-05-28 08:32:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"04510c2c-638c-4687-81d7-b12e76f41df3\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}\n[2026-05-28 08:32:25] local.INFO: [Jiminny\\Jobs\\Mailbox\\CreateBatches] processed 1 inboxes and created 0 batches {\"userId\":null,\"batchSize\":30,\"maxBatches\":1000} {\"correlation_id\":\"e60597ef-aca8-4bda-bb90-18f01e96874d\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-4191285066257905338
|
3613057122943418527
|
visual_change
|
accessibility
|
NULL
|
Committing…
Project: faVsco.js, menu
JY-20915-fix- Committing…
Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
[2026-05-28 08:28:04] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"meeting-bot:schedule-bot","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"73199e23-a066-42ba-b189-2802e0869a44","trace_id":"e53672c2-0f50-409d-af25-84ab485c505d"}
[2026-05-28 08:28:04] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {"count":0} {"correlation_id":"73199e23-a066-42ba-b189-2802e0869a44","trace_id":"e53672c2-0f50-409d-af25-84ab485c505d"}
[2026-05-28 08:28:04] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"meeting-bot:schedule-bot","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"73199e23-a066-42ba-b189-2802e0869a44","trace_id":"e53672c2-0f50-409d-af25-84ab485c505d"}
[2026-05-28 08:28:06] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"dialers:monitor-activities","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"741b2c4e-6a44-4c46-b9fb-fce017aef225","trace_id":"804dc547-eb25-4b32-8d0f-c87019773085"}
[2026-05-28 08:28:06] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"dialers:monitor-activities","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"741b2c4e-6a44-4c46-b9fb-fce017aef225","trace_id":"804dc547-eb25-4b32-8d0f-c87019773085"}
[2026-05-28 08:28:09] local.NOTICE: Monitoring start {"correlation_id":"8ae5c131-edd9-463d-8161-875f4d34320f","trace_id":"1b6420c8-ef4e-4566-81b2-688696064648"}
[2026-05-28 08:28:09] local.NOTICE: Monitoring end {"correlation_id":"8ae5c131-edd9-463d-8161-875f4d34320f","trace_id":"1b6420c8-ef4e-4566-81b2-688696064648"}
[2026-05-28 08:28:10] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"mailbox:skip-lists:refresh","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"6f5390d3-abe7-4e56-a662-aeed1098941b","trace_id":"b57dc2df-2f4d-4d3b-b09a-aa6e61205d5e"}
[2026-05-28 08:28:10] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"mailbox:skip-lists:refresh","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"6f5390d3-abe7-4e56-a662-aeed1098941b","trace_id":"b57dc2df-2f4d-4d3b-b09a-aa6e61205d5e"}
[2026-05-28 08:28:12] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"mailbox:batch:process","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"ba694158-ea28-4ac1-b134-83ac485146e0","trace_id":"83a26b74-baa5-407e-9fc2-2b49d65b1c77"}
[2026-05-28 08:28:12] local.INFO: [EmailSchedule] STARTING batch process {"host":"docker_lamp_1"} {"correlation_id":"ba694158-ea28-4ac1-b134-83ac485146e0","trace_id":"83a26b74-baa5-407e-9fc2-2b49d65b1c77"}
[2026-05-28 08:28:12] local.INFO: [EmailSchedule] FINISHED batch process {"host":"docker_lamp_1","processed":0} {"correlation_id":"ba694158-ea28-4ac1-b134-83ac485146e0","trace_id":"83a26b74-baa5-407e-9fc2-2b49d65b1c77"}
[2026-05-28 08:28:12] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"mailbox:batch:process","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"ba694158-ea28-4ac1-b134-83ac485146e0","trace_id":"83a26b74-baa5-407e-9fc2-2b49d65b1c77"}
[2026-05-28 08:28:14] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"conference:monitor:count","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"b79833c7-3eab-4eb7-98bb-42359039b8fb","trace_id":"a8e159bc-867d-40af-bf7d-1228cf6d4f16"}
[2026-05-28 08:28:14] local.INFO: Running conference:monitor:count command for activities in (2026-05-28 08:26:00, 2026-05-28 08:28:00] {"correlation_id":"b79833c7-3eab-4eb7-98bb-42359039b8fb","trace_id":"a8e159bc-867d-40af-bf7d-1228cf6d4f16"}
[2026-05-28 08:28:14] local.INFO: [conference:monitor:count] No activities found in (2026-05-28 08:26:00, 2026-05-28 08:28:00] {"correlation_id":"b79833c7-3eab-4eb7-98bb-42359039b8fb","trace_id":"a8e159bc-867d-40af-bf7d-1228cf6d4f16"}
[2026-05-28 08:28:14] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"conference:monitor:count","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"b79833c7-3eab-4eb7-98bb-42359039b8fb","trace_id":"a8e159bc-867d-40af-bf7d-1228cf6d4f16"}
[2026-05-28 08:28:16] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"mailbox:batch:retry-failed","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"d51071d5-ead0-45f0-a07e-e3234074f884","trace_id":"77173d9f-596f-405f-ae55-ba117b66455d"}
[2026-05-28 08:28:16] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"calendar:sync","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.NOTICE: Calendar sync start {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"mailbox:batch:retry-failed","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"d51071d5-ead0-45f0-a07e-e3234074f884","trace_id":"77173d9f-596f-405f-ae55-ba117b66455d"}
[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1393,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1393,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1393,"provider":"google","refreshToken":"5aa7e2d96b53201cd16fca5d2e4ef3ad03320971fc064781d18aee3ae7b99fbf","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1393,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Account has been deleted"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1393,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1387,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1387,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1387,"provider":"google","refreshToken":"8157ac6de94842937194009e9c50e459253600f799dacf6a40755ffdbeb5bba6","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1387,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Account has been deleted"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1387,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1348,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1348,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1348,"provider":"google","refreshToken":"9e7d13d3032d0cb1b79d8e95aef01383e8e91eb52ff8ee960c8a0b6b95cd8c73","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1348,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1348,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1361,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1361,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1361,"provider":"google","refreshToken":"6c843da199c2b9907445329304fcc4ec5057a4ee748d8299641764395c08e1fd","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1361,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Account has been deleted"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1361,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1310,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1310,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1310,"provider":"google","refreshToken":"e34818922c2830a660813a63f6169a4a9a992ae2cccd7dc8dd7796cfdb470ef1","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1310,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1310,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1333,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1333,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1333,"provider":"google","refreshToken":"6c902986546d8e8da1dc539b046cdc1d458f519acc972e5b5f1d6a1a295165e0","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1333,"provider":"google","responseBody":{"error":"unauthorized_client","error_description":"Unauthorized"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1333,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1368,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1368,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1368,"provider":"google","refreshToken":"d2f128898ff8543bd16b69cfae37896ab85119b0f5ed2b431d739593bb600333","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1368,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1368,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1365,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1365,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1365,"provider":"google","refreshToken":"7676e4a9afcd082b413248ab5ec6e487021fec6a9bdf315860a59cefad9caad8","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1365,"provider":"google","responseBody":{"error":"unauthorized_client","error_description":"Unauthorized"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1365,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1364,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1364,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1364,"provider":"google","refreshToken":"dd5882ebce76e645292ce33ae74238abbb77c0a4ecc6a2bfe723cad82e72ba8e","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1364,"provider":"google","responseBody":{"error":"unauthorized_client","error_description":"Unauthorized"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1364,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1370,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1370,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1370,"provider":"office","refreshToken":"b7ee8035306d0043cea6e00e7c4fe14f745e44074a1194db62a31cdf8b70af3e","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1370,"provider":"office","responseBody":"{\"error\":\"invalid_client\",\"error_description\":\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 41d8db5c-a91f-41a6-9b5c-22a6c99b9100 Correlation ID: 70bc0a6f-1565-4e74-94dc-419d94108fa9 Timestamp: 2026-05-28 08:28:18Z\",\"error_codes\":[7000215],\"timestamp\":\"2026-05-28 08:28:18Z\",\"trace_id\":\"41d8db5c-a91f-41a6-9b5c-22a6c99b9100\",\"correlation_id\":\"70bc0a6f-1565-4e74-94dc-419d94108fa9\",\"error_uri\":\"https://login.microsoftonline.com/error?code=7000215\"}"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1370,"provider":"office","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1202,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1202,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1202,"provider":"office","refreshToken":"b458799ccc29b21a6e2eb5260fdb63e49ccba21bf942a3973fb63799bd7f0afe","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1202,"provider":"office","responseBody":"{\"error\":\"invalid_client\",\"error_description\":\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: d3d14dfc-1b70-40c4-b9db-fab12f748300 Correlation ID: 4c5f746c-8366-44c1-8733-6877607826db Timestamp: 2026-05-28 08:28:19Z\",\"error_codes\":[7000215],\"timestamp\":\"2026-05-28 08:28:19Z\",\"trace_id\":\"d3d14dfc-1b70-40c4-b9db-fab12f748300\",\"correlation_id\":\"4c5f746c-8366-44c1-8733-6877607826db\",\"error_uri\":\"https://login.microsoftonline.com/error?code=7000215\"}"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1202,"provider":"office","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1502,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1502,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: Calendar sync job dispatched {"calendar_id":501} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1300,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1300,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1300,"provider":"google","refreshToken":"4b811db0725fd9602a95943519a7da935e2a5065da7d9ebfcb170752e3e1ddb8","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1300,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Account has been deleted"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1300,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1409,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1409,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1409,"provider":"google","refreshToken":"e2a3f2d06894894eed1ee87d9db1ace77d4d42ee6e1288a8940ad2c10333b0c4","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1409,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1409,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1352,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1352,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1352,"provider":"google","refreshToken":"dd4b16b00fdc1216da6b717c02338c073636e29162826b2de6db3f064fc029eb","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1352,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1352,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1296,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1296,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1296,"provider":"office","refreshToken":"011ae723c9d800c674e0b4be76f49fc046dac7d501b66c59ef0d9549cfa56ae5","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1502,"provider":"google"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1502,"provider":"google"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [Calendar] Processing sync {"calendarId":"a33076c1-8d97-431a-99f0-85c9524e118b","from":null,"to":null,"delta":"CIiFh8TP44kDEIiFh8TP44kDGAUgkZvkzgIokZvkzgI=","last_sync":"2024-12-09 07:12:53","dateMode":"daily"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"integration-app","crm_owner":1695,"team_id":3143} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1502,"provider":"google"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1502,"provider":"google"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1296,"provider":"office","responseBody":"{\"error\":\"invalid_client\",\"error_description\":\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: dd83a147-95bc-407c-8c9b-3c14e7cb7d00 Correlation ID: bb16bae3-b3c4-467e-bd95-4e7ab85364c9 Timestamp: 2026-05-28 08:28:20Z\",\"error_codes\":[7000215],\"timestamp\":\"2026-05-28 08:28:20Z\",\"trace_id\":\"dd83a147-95bc-407c-8c9b-3c14e7cb7d00\",\"correlation_id\":\"bb16bae3-b3c4-467e-bd95-4e7ab85364c9\",\"error_uri\":\"https://login.microsoftonline.com/error?code=7000215\"}"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1296,"provider":"office","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":391,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":391,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":391,"provider":"office","refreshToken":"00045eebae0f39b34887c6d53f92ae78064f7145e1f4b67754aebd03cfb2d881","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [Google Calendar] Failed to watch channel for calendar {"calendarId":"a33076c1-8d97-431a-99f0-85c9524e118b","code":400,"reason":"{
\"error\": {
\"errors\": [
{
\"domain\": \"global\",
\"reason\": \"push.webhookUrlNotHttps\",
\"message\": \"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\"
}
],
\"code\": 400,
\"message\": \"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\"
}
}"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.WARNING: [Calendar] Sync failed {"calendarId":"a33076c1-8d97-431a-99f0-85c9524e118b","code":400,"reason":"{
\"error\": {
\"errors\": [
{
\"domain\": \"global\",
\"reason\": \"push.webhookUrlNotHttps\",
\"message\": \"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\"
}
],
\"code\": 400,
\"message\": \"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\"
}
}"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":391,"provider":"office","responseBody":"{\"error\":\"invalid_client\",\"error_description\":\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 587224ad-f597-4371-b2ba-00fcd2da1b00 Correlation ID: 4e752610-95b1-4606-847f-68e00f90be0a Timestamp: 2026-05-28 08:28:21Z\",\"error_codes\":[7000215],\"timestamp\":\"2026-05-28 08:28:21Z\",\"trace_id\":\"587224ad-f597-4371-b2ba-00fcd2da1b00\",\"correlation_id\":\"4e752610-95b1-4606-847f-68e00f90be0a\",\"error_uri\":\"https://login.microsoftonline.com/error?code=7000215\"}"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":391,"provider":"office","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1271,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1271,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1271,"provider":"office","refreshToken":"118cde2c06993147b07ccaec4cbcd5026a819dea6c71081166a492933e392afb","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-...
|
81612
|
NULL
|
NULL
|
NULL
|
|
81617
|
2833
|
25
|
2026-05-28T08:32:41.372636+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779957161372_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
remote: Resolving deltas: 100% (10/10), completed remote: Resolving deltas: 100% (10/10), completed with 10 local objects.
2 files committed
JY-20915 fix missing header
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
103
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 08:28:04] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"meeting-bot:schedule-bot","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"73199e23-a066-42ba-b189-2802e0869a44","trace_id":"e53672c2-0f50-409d-af25-84ab485c505d"}
[2026-05-28 08:28:04] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {"count":0} {"correlation_id":"73199e23-a066-42ba-b189-2802e0869a44","trace_id":"e53672c2-0f50-409d-af25-84ab485c505d"}
[2026-05-28 08:28:04] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"meeting-bot:schedule-bot","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"73199e23-a066-42ba-b189-2802e0869a44","trace_id":"e53672c2-0f50-409d-af25-84ab485c505d"}
[2026-05-28 08:28:06] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"dialers:monitor-activities","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"741b2c4e-6a44-4c46-b9fb-fce017aef225","trace_id":"804dc547-eb25-4b32-8d0f-c87019773085"}
[2026-05-28 08:28:06] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"dialers:monitor-activities","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"741b2c4e-6a44-4c46-b9fb-fce017aef225","trace_id":"804dc547-eb25-4b32-8d0f-c87019773085"}
[2026-05-28 08:28:09] local.NOTICE: Monitoring start {"correlation_id":"8ae5c131-edd9-463d-8161-875f4d34320f","trace_id":"1b6420c8-ef4e-4566-81b2-688696064648"}
[2026-05-28 08:28:09] local.NOTICE: Monitoring end {"correlation_id":"8ae5c131-edd9-463d-8161-875f4d34320f","trace_id":"1b6420c8-ef4e-4566-81b2-688696064648"}
[2026-05-28 08:28:10] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"mailbox:skip-lists:refresh","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"6f5390d3-abe7-4e56-a662-aeed1098941b","trace_id":"b57dc2df-2f4d-4d3b-b09a-aa6e61205d5e"}
[2026-05-28 08:28:10] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"mailbox:skip-lists:refresh","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"6f5390d3-abe7-4e56-a662-aeed1098941b","trace_id":"b57dc2df-2f4d-4d3b-b09a-aa6e61205d5e"}
[2026-05-28 08:28:12] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"mailbox:batch:process","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"ba694158-ea28-4ac1-b134-83ac485146e0","trace_id":"83a26b74-baa5-407e-9fc2-2b49d65b1c77"}
[2026-05-28 08:28:12] local.INFO: [EmailSchedule] STARTING batch process {"host":"docker_lamp_1"} {"correlation_id":"ba694158-ea28-4ac1-b134-83ac485146e0","trace_id":"83a26b74-baa5-407e-9fc2-2b49d65b1c77"}
[2026-05-28 08:28:12] local.INFO: [EmailSchedule] FINISHED batch process {"host":"docker_lamp_1","processed":0} {"correlation_id":"ba694158-ea28-4ac1-b134-83ac485146e0","trace_id":"83a26b74-baa5-407e-9fc2-2b49d65b1c77"}
[2026-05-28 08:28:12] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"mailbox:batch:process","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"ba694158-ea28-4ac1-b134-83ac485146e0","trace_id":"83a26b74-baa5-407e-9fc2-2b49d65b1c77"}
[2026-05-28 08:28:14] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"conference:monitor:count","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"b79833c7-3eab-4eb7-98bb-42359039b8fb","trace_id":"a8e159bc-867d-40af-bf7d-1228cf6d4f16"}
[2026-05-28 08:28:14] local.INFO: Running conference:monitor:count command for activities in (2026-05-28 08:26:00, 2026-05-28 08:28:00] {"correlation_id":"b79833c7-3eab-4eb7-98bb-42359039b8fb","trace_id":"a8e159bc-867d-40af-bf7d-1228cf6d4f16"}
[2026-05-28 08:28:14] local.INFO: [conference:monitor:count] No activities found in (2026-05-28 08:26:00, 2026-05-28 08:28:00] {"correlation_id":"b79833c7-3eab-4eb7-98bb-42359039b8fb","trace_id":"a8e159bc-867d-40af-bf7d-1228cf6d4f16"}
[2026-05-28 08:28:14] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"conference:monitor:count","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"b79833c7-3eab-4eb7-98bb-42359039b8fb","trace_id":"a8e159bc-867d-40af-bf7d-1228cf6d4f16"}
[2026-05-28 08:28:16] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"mailbox:batch:retry-failed","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"d51071d5-ead0-45f0-a07e-e3234074f884","trace_id":"77173d9f-596f-405f-ae55-ba117b66455d"}
[2026-05-28 08:28:16] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"calendar:sync","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.NOTICE: Calendar sync start {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"mailbox:batch:retry-failed","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"d51071d5-ead0-45f0-a07e-e3234074f884","trace_id":"77173d9f-596f-405f-ae55-ba117b66455d"}
[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1393,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1393,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1393,"provider":"google","refreshToken":"5aa7e2d96b53201cd16fca5d2e4ef3ad03320971fc064781d18aee3ae7b99fbf","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1393,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Account has been deleted"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1393,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1387,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1387,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1387,"provider":"google","refreshToken":"8157ac6de94842937194009e9c50e459253600f799dacf6a40755ffdbeb5bba6","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1387,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Account has been deleted"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1387,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1348,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1348,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1348,"provider":"google","refreshToken":"9e7d13d3032d0cb1b79d8e95aef01383e8e91eb52ff8ee960c8a0b6b95cd8c73","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1348,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1348,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1361,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1361,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1361,"provider":"google","refreshToken":"6c843da199c2b9907445329304fcc4ec5057a4ee748d8299641764395c08e1fd","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1361,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Account has been deleted"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1361,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1310,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1310,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1310,"provider":"google","refreshToken":"e34818922c2830a660813a63f6169a4a9a992ae2cccd7dc8dd7796cfdb470ef1","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1310,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1310,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1333,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1333,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1333,"provider":"google","refreshToken":"6c902986546d8e8da1dc539b046cdc1d458f519acc972e5b5f1d6a1a295165e0","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1333,"provider":"google","responseBody":{"error":"unauthorized_client","error_description":"Unauthorized"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1333,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1368,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1368,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1368,"provider":"google","refreshToken":"d2f128898ff8543bd16b69cfae37896ab85119b0f5ed2b431d739593bb600333","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1368,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1368,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1365,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1365,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1365,"provider":"google","refreshToken":"7676e4a9afcd082b413248ab5ec6e487021fec6a9bdf315860a59cefad9caad8","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1365,"provider":"google","responseBody":{"error":"unauthorized_client","error_description":"Unauthorized"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1365,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1364,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1364,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1364,"provider":"google","refreshToken":"dd5882ebce76e645292ce33ae74238abbb77c0a4ecc6a2bfe723cad82e72ba8e","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1364,"provider":"google","responseBody":{"error":"unauthorized_client","error_description":"Unauthorized"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1364,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1370,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1370,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1370,"provider":"office","refreshToken":"b7ee8035306d0043cea6e00e7c4fe14f745e44074a1194db62a31cdf8b70af3e","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1370,"provider":"office","responseBody":"{\"error\":\"invalid_client\",\"error_description\":\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 41d8db5c-a91f-41a6-9b5c-22a6c99b9100 Correlation ID: 70bc0a6f-1565-4e74-94dc-419d94108fa9 Timestamp: 2026-05-28 08:28:18Z\",\"error_codes\":[7000215],\"timestamp\":\"2026-05-28 08:28:18Z\",\"trace_id\":\"41d8db5c-a91f-41a6-9b5c-22a6c99b9100\",\"correlation_id\":\"70bc0a6f-1565-4e74-94dc-419d94108fa9\",\"error_uri\":\"https://login.microsoftonline.com/error?code=7000215\"}"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1370,"provider":"office","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1202,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1202,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1202,"provider":"office","refreshToken":"b458799ccc29b21a6e2eb5260fdb63e49ccba21bf942a3973fb63799bd7f0afe","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1202,"provider":"office","responseBody":"{\"error\":\"invalid_client\",\"error_description\":\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: d3d14dfc-1b70-40c4-b9db-fab12f748300 Correlation ID: 4c5f746c-8366-44c1-8733-6877607826db Timestamp: 2026-05-28 08:28:19Z\",\"error_codes\":[7000215],\"timestamp\":\"2026-05-28 08:28:19Z\",\"trace_id\":\"d3d14dfc-1b70-40c4-b9db-fab12f748300\",\"correlation_id\":\"4c5f746c-8366-44c1-8733-6877607826db\",\"error_uri\":\"https://login.microsoftonline.com/error?code=7000215\"}"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1202,"provider":"office","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1502,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1502,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: Calendar sync job dispatched {"calendar_id":501} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1300,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1300,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1300,"provider":"google","refreshToken":"4b811db0725fd9602a95943519a7da935e2a5065da7d9ebfcb170752e3e1ddb8","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1300,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Account has been deleted"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1300,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1409,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1409,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1409,"provider":"google","refreshToken":"e2a3f2d06894894eed1ee87d9db1ace77d4d42ee6e1288a8940ad2c10333b0c4","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1409,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1409,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1352,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1352,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1352,"provider":"google","refreshToken":"dd4b16b00fdc1216da6b717c02338c073636e29162826b2de6db3f064fc029eb","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1352,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1352,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1296,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1296,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1296,"provider":"office","refreshToken":"011ae723c9d800c674e0b4be76f49fc046dac7d501b66c59ef0d9549cfa56ae5","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1502,"provider":"google"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1502,"provider":"google"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [Calendar] Processing sync {"calendarId":"a33076c1-8d97-431a-99f0-85c9524e118b","from":null,"to":null,"delta":"CIiFh8TP44kDEIiFh8TP44kDGAUgkZvkzgIokZvkzgI=","last_sync":"2024-12-09 07:12:53","dateMode":"daily"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"integration-app","crm_owner":1695,"team_id":3143} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1502,"provider":"google"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1502,"provider":"google"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1296,"provider":"office","responseBody":"{\"error\":\"invalid_client\",\"error_description\":\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: dd83a147-95bc-407c-8c9b-3c14e7cb7d00 Correlation ID: bb16bae3-b3c4-467e-bd95-4e7ab85364c9 Timestamp: 2026-05-28 08:28:20Z\",\"error_codes\":[7000215],\"timestamp\":\"2026-05-28 08:28:20Z\",\"trace_id\":\"dd83a147-95bc-407c-8c9b-3c14e7cb7d00\",\"correlation_id\":\"bb16bae3-b3c4-467e-bd95-4e7ab85364c9\",\"error_uri\":\"https://login.microsoftonline.com/error?code=7000215\"}"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1296,"provider":"office","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":391,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":391,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":391,"provider":"office","refreshToken":"00045eebae0f39b34887c6d53f92ae78064f7145e1f4b67754aebd03cfb2d881","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [Google Calendar] Failed to watch channel for calendar {"calendarId":"a33076c1-8d97-431a-99f0-85c9524e118b","code":400,"reason":"{
\"error\": {
\"errors\": [
{
\"domain\": \"global\",
\"reason\": \"push.webhookUrlNotHttps\",
\"message\": \"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\"
}
],
\"code\": 400,
\"message\": \"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\"
}
}"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.WARNING: [Calendar] Sync failed {"calendarId":"a33076c1-8d97-431a-99f0-85c9524e118b","code":400,"reason":"{
\"error\": {
\"errors\": [
{
\"domain\": \"global\",
\"reason\": \"push.webhookUrlNotHttps\",
\"message\": \"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\"
}
],
\"code\": 400,
\"message\": \"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\"
}
}"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":391,"provider":"office","responseBody":"{\"error\":\"invalid_client\",\"error_description\":\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 587224ad-f597-4371-b2ba-00fcd2da1b00 Correlation ID: 4e752610-95b1-4606-847f-68e00f90be0a Timestamp: 2026-05-28 08:28:21Z\",\"error_codes\":[7000215],\"timestamp\":\"2026-05-28 08:28:21Z\",\"trace_id\":\"587224ad-f597-4371-b2ba-00fcd2da1b00\",\"correlation_id\":\"4e752610-95b1-4606-847f-68e00f90be0a\",\"error_uri\":\"https://login.microsoftonline.com/error?code=7000215\"}"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":391,"provider":"office","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1271,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1271,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Re...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"","depth":2,"bounds":{"left":0.6625665,"top":0.44134077,"width":0.06948138,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"remote: Resolving deltas: 100% (10/10), completed with 10 local objects.","depth":2,"bounds":{"left":0.6625665,"top":0.47326416,"width":0.06948138,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2 files committed","depth":2,"bounds":{"left":0.8753325,"top":0.91300875,"width":0.100398935,"height":0.013567438},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"JY-20915 fix missing header","depth":3,"bounds":{"left":0.8753325,"top":0.92897046,"width":0.11037234,"height":0.013567438},"on_screen":true,"value":"JY-20915 fix missing header","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.92897046,"width":0.05817819,"height":0.013567438},"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"bounds":{"left":0.8753325,"top":0.9481245,"width":0.048204787,"height":0.013567438},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09740692,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8374335,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"bounds":{"left":0.85272604,"top":0.019952115,"width":0.062832445,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.37632978,"top":0.10055866,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"15","depth":4,"bounds":{"left":0.3856383,"top":0.10055866,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.39694148,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.40425533,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"103","depth":4,"bounds":{"left":0.72539896,"top":0.10055866,"width":0.011968086,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.7390292,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.7463431,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-28 08:28:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"73199e23-a066-42ba-b189-2802e0869a44\",\"trace_id\":\"e53672c2-0f50-409d-af25-84ab485c505d\"}\n[2026-05-28 08:28:04] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"73199e23-a066-42ba-b189-2802e0869a44\",\"trace_id\":\"e53672c2-0f50-409d-af25-84ab485c505d\"}\n[2026-05-28 08:28:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"73199e23-a066-42ba-b189-2802e0869a44\",\"trace_id\":\"e53672c2-0f50-409d-af25-84ab485c505d\"}\n[2026-05-28 08:28:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"741b2c4e-6a44-4c46-b9fb-fce017aef225\",\"trace_id\":\"804dc547-eb25-4b32-8d0f-c87019773085\"}\n[2026-05-28 08:28:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"741b2c4e-6a44-4c46-b9fb-fce017aef225\",\"trace_id\":\"804dc547-eb25-4b32-8d0f-c87019773085\"}\n[2026-05-28 08:28:09] local.NOTICE: Monitoring start {\"correlation_id\":\"8ae5c131-edd9-463d-8161-875f4d34320f\",\"trace_id\":\"1b6420c8-ef4e-4566-81b2-688696064648\"}\n[2026-05-28 08:28:09] local.NOTICE: Monitoring end {\"correlation_id\":\"8ae5c131-edd9-463d-8161-875f4d34320f\",\"trace_id\":\"1b6420c8-ef4e-4566-81b2-688696064648\"}\n[2026-05-28 08:28:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"6f5390d3-abe7-4e56-a662-aeed1098941b\",\"trace_id\":\"b57dc2df-2f4d-4d3b-b09a-aa6e61205d5e\"}\n[2026-05-28 08:28:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"6f5390d3-abe7-4e56-a662-aeed1098941b\",\"trace_id\":\"b57dc2df-2f4d-4d3b-b09a-aa6e61205d5e\"}\n[2026-05-28 08:28:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"ba694158-ea28-4ac1-b134-83ac485146e0\",\"trace_id\":\"83a26b74-baa5-407e-9fc2-2b49d65b1c77\"}\n[2026-05-28 08:28:12] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"ba694158-ea28-4ac1-b134-83ac485146e0\",\"trace_id\":\"83a26b74-baa5-407e-9fc2-2b49d65b1c77\"}\n[2026-05-28 08:28:12] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"ba694158-ea28-4ac1-b134-83ac485146e0\",\"trace_id\":\"83a26b74-baa5-407e-9fc2-2b49d65b1c77\"}\n[2026-05-28 08:28:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"ba694158-ea28-4ac1-b134-83ac485146e0\",\"trace_id\":\"83a26b74-baa5-407e-9fc2-2b49d65b1c77\"}\n[2026-05-28 08:28:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"b79833c7-3eab-4eb7-98bb-42359039b8fb\",\"trace_id\":\"a8e159bc-867d-40af-bf7d-1228cf6d4f16\"}\n[2026-05-28 08:28:14] local.INFO: Running conference:monitor:count command for activities in (2026-05-28 08:26:00, 2026-05-28 08:28:00] {\"correlation_id\":\"b79833c7-3eab-4eb7-98bb-42359039b8fb\",\"trace_id\":\"a8e159bc-867d-40af-bf7d-1228cf6d4f16\"}\n[2026-05-28 08:28:14] local.INFO: [conference:monitor:count] No activities found in (2026-05-28 08:26:00, 2026-05-28 08:28:00] {\"correlation_id\":\"b79833c7-3eab-4eb7-98bb-42359039b8fb\",\"trace_id\":\"a8e159bc-867d-40af-bf7d-1228cf6d4f16\"}\n[2026-05-28 08:28:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"b79833c7-3eab-4eb7-98bb-42359039b8fb\",\"trace_id\":\"a8e159bc-867d-40af-bf7d-1228cf6d4f16\"}\n[2026-05-28 08:28:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"d51071d5-ead0-45f0-a07e-e3234074f884\",\"trace_id\":\"77173d9f-596f-405f-ae55-ba117b66455d\"}\n[2026-05-28 08:28:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"calendar:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.NOTICE: Calendar sync start {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"d51071d5-ead0-45f0-a07e-e3234074f884\",\"trace_id\":\"77173d9f-596f-405f-ae55-ba117b66455d\"}\n[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1393,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1393,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1393,\"provider\":\"google\",\"refreshToken\":\"5aa7e2d96b53201cd16fca5d2e4ef3ad03320971fc064781d18aee3ae7b99fbf\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1393,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1393,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1387,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1387,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1387,\"provider\":\"google\",\"refreshToken\":\"8157ac6de94842937194009e9c50e459253600f799dacf6a40755ffdbeb5bba6\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1387,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1387,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1348,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1348,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1348,\"provider\":\"google\",\"refreshToken\":\"9e7d13d3032d0cb1b79d8e95aef01383e8e91eb52ff8ee960c8a0b6b95cd8c73\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1348,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1348,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1361,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1361,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1361,\"provider\":\"google\",\"refreshToken\":\"6c843da199c2b9907445329304fcc4ec5057a4ee748d8299641764395c08e1fd\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1361,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1361,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1310,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1310,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1310,\"provider\":\"google\",\"refreshToken\":\"e34818922c2830a660813a63f6169a4a9a992ae2cccd7dc8dd7796cfdb470ef1\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1310,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1310,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1333,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1333,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1333,\"provider\":\"google\",\"refreshToken\":\"6c902986546d8e8da1dc539b046cdc1d458f519acc972e5b5f1d6a1a295165e0\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1333,\"provider\":\"google\",\"responseBody\":{\"error\":\"unauthorized_client\",\"error_description\":\"Unauthorized\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1333,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1368,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1368,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1368,\"provider\":\"google\",\"refreshToken\":\"d2f128898ff8543bd16b69cfae37896ab85119b0f5ed2b431d739593bb600333\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1368,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1368,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1365,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1365,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1365,\"provider\":\"google\",\"refreshToken\":\"7676e4a9afcd082b413248ab5ec6e487021fec6a9bdf315860a59cefad9caad8\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1365,\"provider\":\"google\",\"responseBody\":{\"error\":\"unauthorized_client\",\"error_description\":\"Unauthorized\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1365,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1364,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1364,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1364,\"provider\":\"google\",\"refreshToken\":\"dd5882ebce76e645292ce33ae74238abbb77c0a4ecc6a2bfe723cad82e72ba8e\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1364,\"provider\":\"google\",\"responseBody\":{\"error\":\"unauthorized_client\",\"error_description\":\"Unauthorized\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1364,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1370,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1370,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1370,\"provider\":\"office\",\"refreshToken\":\"b7ee8035306d0043cea6e00e7c4fe14f745e44074a1194db62a31cdf8b70af3e\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1370,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 41d8db5c-a91f-41a6-9b5c-22a6c99b9100 Correlation ID: 70bc0a6f-1565-4e74-94dc-419d94108fa9 Timestamp: 2026-05-28 08:28:18Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:18Z\\\",\\\"trace_id\\\":\\\"41d8db5c-a91f-41a6-9b5c-22a6c99b9100\\\",\\\"correlation_id\\\":\\\"70bc0a6f-1565-4e74-94dc-419d94108fa9\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1370,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1202,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1202,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1202,\"provider\":\"office\",\"refreshToken\":\"b458799ccc29b21a6e2eb5260fdb63e49ccba21bf942a3973fb63799bd7f0afe\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1202,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: d3d14dfc-1b70-40c4-b9db-fab12f748300 Correlation ID: 4c5f746c-8366-44c1-8733-6877607826db Timestamp: 2026-05-28 08:28:19Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:19Z\\\",\\\"trace_id\\\":\\\"d3d14dfc-1b70-40c4-b9db-fab12f748300\\\",\\\"correlation_id\\\":\\\"4c5f746c-8366-44c1-8733-6877607826db\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1202,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: Calendar sync job dispatched {\"calendar_id\":501} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1300,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1300,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1300,\"provider\":\"google\",\"refreshToken\":\"4b811db0725fd9602a95943519a7da935e2a5065da7d9ebfcb170752e3e1ddb8\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1300,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1300,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1409,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1409,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1409,\"provider\":\"google\",\"refreshToken\":\"e2a3f2d06894894eed1ee87d9db1ace77d4d42ee6e1288a8940ad2c10333b0c4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1409,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1409,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1352,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1352,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1352,\"provider\":\"google\",\"refreshToken\":\"dd4b16b00fdc1216da6b717c02338c073636e29162826b2de6db3f064fc029eb\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1352,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1352,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1296,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1296,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1296,\"provider\":\"office\",\"refreshToken\":\"011ae723c9d800c674e0b4be76f49fc046dac7d501b66c59ef0d9549cfa56ae5\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [Calendar] Processing sync {\"calendarId\":\"a33076c1-8d97-431a-99f0-85c9524e118b\",\"from\":null,\"to\":null,\"delta\":\"CIiFh8TP44kDEIiFh8TP44kDGAUgkZvkzgIokZvkzgI=\",\"last_sync\":\"2024-12-09 07:12:53\",\"dateMode\":\"daily\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"integration-app\",\"crm_owner\":1695,\"team_id\":3143} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1296,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: dd83a147-95bc-407c-8c9b-3c14e7cb7d00 Correlation ID: bb16bae3-b3c4-467e-bd95-4e7ab85364c9 Timestamp: 2026-05-28 08:28:20Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:20Z\\\",\\\"trace_id\\\":\\\"dd83a147-95bc-407c-8c9b-3c14e7cb7d00\\\",\\\"correlation_id\\\":\\\"bb16bae3-b3c4-467e-bd95-4e7ab85364c9\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1296,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":391,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":391,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":391,\"provider\":\"office\",\"refreshToken\":\"00045eebae0f39b34887c6d53f92ae78064f7145e1f4b67754aebd03cfb2d881\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [Google Calendar] Failed to watch channel for calendar {\"calendarId\":\"a33076c1-8d97-431a-99f0-85c9524e118b\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.WARNING: [Calendar] Sync failed {\"calendarId\":\"a33076c1-8d97-431a-99f0-85c9524e118b\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":391,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 587224ad-f597-4371-b2ba-00fcd2da1b00 Correlation ID: 4e752610-95b1-4606-847f-68e00f90be0a Timestamp: 2026-05-28 08:28:21Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:21Z\\\",\\\"trace_id\\\":\\\"587224ad-f597-4371-b2ba-00fcd2da1b00\\\",\\\"correlation_id\\\":\\\"4e752610-95b1-4606-847f-68e00f90be0a\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":391,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1271,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1271,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1271,\"provider\":\"office\",\"refreshToken\":\"118cde2c06993147b07ccaec4cbcd5026a819dea6c71081166a492933e392afb\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1271,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: dd8bf2a7-bc49-43d7-a487-892c51e27600 Correlation ID: 51e3eb6c-c47e-4dd7-91aa-e734fe5b65cf Timestamp: 2026-05-28 08:28:21Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:21Z\\\",\\\"trace_id\\\":\\\"dd8bf2a7-bc49-43d7-a487-892c51e27600\\\",\\\"correlation_id\\\":\\\"51e3eb6c-c47e-4dd7-91aa-e734fe5b65cf\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1271,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1351,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1351,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1351,\"provider\":\"google\",\"refreshToken\":\"4271d15b9e60a606439caddc68337f783e472c85b03dacff14d1b6dfded9051c\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1351,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1351,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1366,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1366,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1366,\"provider\":\"google\",\"refreshToken\":\"ae21385059b2eebfd43f68aecd56eccd702a1aabb6598f1f7ab594ed8af491b4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1366,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1366,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: Calendar sync job dispatched {\"calendar_id\":378} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: Calendar sync job dispatched {\"calendar_id\":504} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.NOTICE: Calendar sync end {\"retrieved_calendars\":31,\"processed_calendars\":3} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"calendar:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [Calendar] Processing sync {\"calendarId\":\"2676cb6d-f86c-427e-bf78-591e388e3c1e\",\"from\":null,\"to\":null,\"delta\":\"CJ_x49O3jpIDEJ_x49O3jpIDGAUgw67KlwMow67KlwM=\",\"last_sync\":\"2026-01-19 07:48:40\",\"dateMode\":\"daily\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.WARNING: [Pipedrive] Account not connected for user {\"userId\":\"e6538737-e7b4-455f-a37a-3e79b665a220\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":1116,\"sociable_id\":241,\"provider_user_id\":\"19555731\",\"expires\":1779091997,\"refresh_token_expires\":null,\"provider\":\"pipedrive\",\"state\":\"full-refresh\",\"auth_scope\":\"base,deals:full,activities:full,contacts:full,search:read\",\"retry_after\":null,\"created_at\":\"2023-09-08 09:44:29\",\"updated_at\":\"2026-05-18 08:13:32\"}}} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"pipedrive\",\"crm_owner\":241,\"team_id\":19} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"pipedrive\",\"team_id\":19} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"pipedrive\",\"team_id\":19} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.WARNING: [Calendar] CRM disconnected for user so events will not be matched {\"provider\":\"pipedrive\",\"user_id\":241,\"message\":\"Your Pipedrive account has become disconnected. Please login to Jiminny to reconnect.\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [Google Calendar] Failed to watch channel for calendar {\"calendarId\":\"2676cb6d-f86c-427e-bf78-591e388e3c1e\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.WARNING: [Calendar] Sync failed {\"calendarId\":\"2676cb6d-f86c-427e-bf78-591e388e3c1e\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [Calendar] Processing sync {\"calendarId\":\"9e8b1a2c-1a8f-42bd-b161-810fc0baf540\",\"from\":null,\"to\":null,\"delta\":\"R0usmcdvmMuZCBYV0hguCBhf4uKqyU9_gdNd-le_nqqau95XAUmZwlIAy2uwtCf5sA67w6NIiDvawUSmVjpTzZO-RsxLdeS-g8Kxy6ODZQxAxafq8AJNx0hJV7T291NUvfaPYqLMv-3je3IdhAPUtXQXkHtYaBAlX_DDBxwc3zYoVVQ8iM9mQkBykdA3sh-KVYPyzi7nK4cZg5Jzpu9tHA.UA7urx3pJyhUhdo_16STIbSNXUrF-qeQVIis9stVUeY\",\"last_sync\":\"2026-05-28 07:44:06\",\"dateMode\":\"daily\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":89,\"team_id\":2} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [MS Office Calendar] Skipping delta sync for daily mode {\"calendarId\":\"9e8b1a2c-1a8f-42bd-b161-810fc0baf540\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:29:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"86a65904-a9f8-43c9-b0c3-1e9c8b4b9541\",\"trace_id\":\"800b02ff-3553-46a3-a8c6-c12324a1ce53\"}\n[2026-05-28 08:29:05] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"86a65904-a9f8-43c9-b0c3-1e9c8b4b9541\",\"trace_id\":\"800b02ff-3553-46a3-a8c6-c12324a1ce53\"}\n[2026-05-28 08:29:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"86a65904-a9f8-43c9-b0c3-1e9c8b4b9541\",\"trace_id\":\"800b02ff-3553-46a3-a8c6-c12324a1ce53\"}\n[2026-05-28 08:29:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"e5162656-5b49-4857-9917-f0cf3ddffe27\",\"trace_id\":\"a3a53cc5-596d-474c-b9c4-f6c5f7ebdfd0\"}\n[2026-05-28 08:29:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"e5162656-5b49-4857-9917-f0cf3ddffe27\",\"trace_id\":\"a3a53cc5-596d-474c-b9c4-f6c5f7ebdfd0\"}\n[2026-05-28 08:29:09] local.NOTICE: Monitoring start {\"correlation_id\":\"f559463e-0c12-46df-8b53-0c50cf4aa3eb\",\"trace_id\":\"5a09aee9-5f75-4bfa-93e4-df0ff76f2326\"}\n[2026-05-28 08:29:09] local.NOTICE: Monitoring end {\"correlation_id\":\"f559463e-0c12-46df-8b53-0c50cf4aa3eb\",\"trace_id\":\"5a09aee9-5f75-4bfa-93e4-df0ff76f2326\"}\n[2026-05-28 08:29:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"9b1cc2f1-0c8a-4aa0-a9e8-57ac879839e4\",\"trace_id\":\"d69dd133-b5f0-4568-81ef-9cce3d1c5c9e\"}\n[2026-05-28 08:29:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"9b1cc2f1-0c8a-4aa0-a9e8-57ac879839e4\",\"trace_id\":\"d69dd133-b5f0-4568-81ef-9cce3d1c5c9e\"}\n[2026-05-28 08:29:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"87e10603-9e6f-4d71-97ab-5ba67103e5fd\",\"trace_id\":\"0aae0afb-779f-4999-892d-0188e14b3dcb\"}\n[2026-05-28 08:29:12] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"87e10603-9e6f-4d71-97ab-5ba67103e5fd\",\"trace_id\":\"0aae0afb-779f-4999-892d-0188e14b3dcb\"}\n[2026-05-28 08:29:12] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"87e10603-9e6f-4d71-97ab-5ba67103e5fd\",\"trace_id\":\"0aae0afb-779f-4999-892d-0188e14b3dcb\"}\n[2026-05-28 08:29:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"87e10603-9e6f-4d71-97ab-5ba67103e5fd\",\"trace_id\":\"0aae0afb-779f-4999-892d-0188e14b3dcb\"}\n[2026-05-28 08:30:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"200b132b-d8db-4010-b968-fe5e3fcc42f1\",\"trace_id\":\"7457715a-3b9d-4c35-a499-455c83e925ab\"}\n[2026-05-28 08:30:04] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"200b132b-d8db-4010-b968-fe5e3fcc42f1\",\"trace_id\":\"7457715a-3b9d-4c35-a499-455c83e925ab\"}\n[2026-05-28 08:30:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"200b132b-d8db-4010-b968-fe5e3fcc42f1\",\"trace_id\":\"7457715a-3b9d-4c35-a499-455c83e925ab\"}\n[2026-05-28 08:30:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"a94ef973-dee7-4bdf-99aa-9ff06f5a5561\",\"trace_id\":\"4e37013f-2993-4c71-87d9-560f8f429d27\"}\n[2026-05-28 08:30:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"a94ef973-dee7-4bdf-99aa-9ff06f5a5561\",\"trace_id\":\"4e37013f-2993-4c71-87d9-560f8f429d27\"}\n[2026-05-28 08:30:07] local.NOTICE: Monitoring start {\"correlation_id\":\"691e7103-784d-4b4a-8036-f3c624a186db\",\"trace_id\":\"991dd947-ed80-4080-8769-8ee7efc4e6a4\"}\n[2026-05-28 08:30:07] local.NOTICE: Monitoring end {\"correlation_id\":\"691e7103-784d-4b4a-8036-f3c624a186db\",\"trace_id\":\"991dd947-ed80-4080-8769-8ee7efc4e6a4\"}\n[2026-05-28 08:30:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"00cf8914-d440-4826-a079-ee4586e76c62\",\"trace_id\":\"d77009ee-8d7b-44ae-bb21-2080b6d48c6c\"}\n[2026-05-28 08:30:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"00cf8914-d440-4826-a079-ee4586e76c62\",\"trace_id\":\"d77009ee-8d7b-44ae-bb21-2080b6d48c6c\"}\n[2026-05-28 08:30:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"7c9550d0-42ed-4b1d-b5b3-7dca67f743ec\",\"trace_id\":\"84177853-9530-4b1e-bde6-3dc0c71883ee\"}\n[2026-05-28 08:30:10] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"7c9550d0-42ed-4b1d-b5b3-7dca67f743ec\",\"trace_id\":\"84177853-9530-4b1e-bde6-3dc0c71883ee\"}\n[2026-05-28 08:30:10] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"7c9550d0-42ed-4b1d-b5b3-7dca67f743ec\",\"trace_id\":\"84177853-9530-4b1e-bde6-3dc0c71883ee\"}\n[2026-05-28 08:30:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"7c9550d0-42ed-4b1d-b5b3-7dca67f743ec\",\"trace_id\":\"84177853-9530-4b1e-bde6-3dc0c71883ee\"}\n[2026-05-28 08:30:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"85cc6c92-262b-45c5-bbcc-4a084137fde3\",\"trace_id\":\"058bc9a3-67af-49b6-a87c-8a0a0bc0c47a\"}\n[2026-05-28 08:30:12] local.INFO: Running conference:monitor:count command for activities in (2026-05-28 08:28:00, 2026-05-28 08:30:00] {\"correlation_id\":\"85cc6c92-262b-45c5-bbcc-4a084137fde3\",\"trace_id\":\"058bc9a3-67af-49b6-a87c-8a0a0bc0c47a\"}\n[2026-05-28 08:30:12] local.INFO: [conference:monitor:count] No activities found in (2026-05-28 08:28:00, 2026-05-28 08:30:00] {\"correlation_id\":\"85cc6c92-262b-45c5-bbcc-4a084137fde3\",\"trace_id\":\"058bc9a3-67af-49b6-a87c-8a0a0bc0c47a\"}\n[2026-05-28 08:30:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"85cc6c92-262b-45c5-bbcc-4a084137fde3\",\"trace_id\":\"058bc9a3-67af-49b6-a87c-8a0a0bc0c47a\"}\n[2026-05-28 08:30:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"5083d024-d669-4c6a-bde3-ce084d6a628c\",\"trace_id\":\"83110e1f-4309-4f4a-b8bb-eab5c0ec081e\"}\n[2026-05-28 08:30:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"5083d024-d669-4c6a-bde3-ce084d6a628c\",\"trace_id\":\"83110e1f-4309-4f4a-b8bb-eab5c0ec081e\"}\n[2026-05-28 08:30:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"bc529b16-9502-4df3-b2c0-c63fcf977ed5\",\"trace_id\":\"9dd5d6d0-4cc5-454c-a0c8-0e72b69eeb29\"}\n[2026-05-28 08:30:15] local.INFO: [TextRelayService] Starting sync {\"mailbox\":\"catch-all@txt.staging.jiminny.com\",\"expected_alias\":\"catch-all\",\"expected_host\":\"txt.staging.jiminny.com\"} {\"correlation_id\":\"bc529b16-9502-4df3-b2c0-c63fcf977ed5\",\"trace_id\":\"9dd5d6d0-4cc5-454c-a0c8-0e72b69eeb29\"}\n[2026-05-28 08:30:15] local.INFO: [TextRelayService] Sync completed {\"mailbox\":\"catch-all@txt.staging.jiminny.com\",\"messages_processed\":0,\"message_ids\":[]} {\"correlation_id\":\"bc529b16-9502-4df3-b2c0-c63fcf977ed5\",\"trace_id\":\"9dd5d6d0-4cc5-454c-a0c8-0e72b69eeb29\"}\n[2026-05-28 08:30:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"bc529b16-9502-4df3-b2c0-c63fcf977ed5\",\"trace_id\":\"9dd5d6d0-4cc5-454c-a0c8-0e72b69eeb29\"}\n[2026-05-28 08:30:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"b655bca8-effa-420b-8686-95ba96f27085\",\"trace_id\":\"b1f43a19-c7ad-428e-9933-4e509b5f0055\"}\n[2026-05-28 08:30:18] local.INFO: Running pre-meeting notification command {\"correlation_id\":\"b655bca8-effa-420b-8686-95ba96f27085\",\"trace_id\":\"b1f43a19-c7ad-428e-9933-4e509b5f0055\"}\n[2026-05-28 08:30:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"b655bca8-effa-420b-8686-95ba96f27085\",\"trace_id\":\"b1f43a19-c7ad-428e-9933-4e509b5f0055\"}\n[2026-05-28 08:30:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"5a8493c4-3ef7-4453-98b7-f32225d453fe\",\"trace_id\":\"056f1aea-8825-4e2c-8239-7804086e504e\"}\n[2026-05-28 08:30:20] local.INFO: Running conference:monitor:start command for activities in (2026-05-28 08:20:00, 2026-05-28 08:25:00] {\"correlation_id\":\"5a8493c4-3ef7-4453-98b7-f32225d453fe\",\"trace_id\":\"056f1aea-8825-4e2c-8239-7804086e504e\"}\n[2026-05-28 08:30:20] local.INFO: [conference:monitor:start] No activities found in (2026-05-28 08:20:00, 2026-05-28 08:25:00] {\"correlation_id\":\"5a8493c4-3ef7-4453-98b7-f32225d453fe\",\"trace_id\":\"056f1aea-8825-4e2c-8239-7804086e504e\"}\n[2026-05-28 08:30:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"5a8493c4-3ef7-4453-98b7-f32225d453fe\",\"trace_id\":\"056f1aea-8825-4e2c-8239-7804086e504e\"}\n[2026-05-28 08:30:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"18a2aed9-1aae-4b10-a7fa-f75a147db499\",\"trace_id\":\"fff0c9b2-1c60-4402-b30a-2f41d9b45db3\"}\n[2026-05-28 08:30:22] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesEnded {\"from\":\"08:25\",\"to\":\"08:30\"} {\"correlation_id\":\"18a2aed9-1aae-4b10-a7fa-f75a147db499\",\"trace_id\":\"fff0c9b2-1c60-4402-b30a-2f41d9b45db3\"}\n[2026-05-28 08:30:22] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesWithUnfinishedSession {\"from\":\"22:20\",\"to\":\"22:25\"} {\"correlation_id\":\"18a2aed9-1aae-4b10-a7fa-f75a147db499\",\"trace_id\":\"fff0c9b2-1c60-4402-b30a-2f41d9b45db3\"}\n[2026-05-28 08:30:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"18a2aed9-1aae-4b10-a7fa-f75a147db499\",\"trace_id\":\"fff0c9b2-1c60-4402-b30a-2f41d9b45db3\"}\n[2026-05-28 08:30:23] local.NOTICE: Repairing HubSpot tokens start {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:23] local.INFO: Trying to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:23] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:23] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":59,\"provider\":\"hubspot\",\"refreshToken\":\"97b78f6e2cc49965c00c2492b602b02708b1392551e6b3f113fbaa48992af90b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:26] local.ERROR: Failed to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:26] local.INFO: Trying to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:26] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:26] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":306,\"provider\":\"hubspot\",\"refreshToken\":\"6fa6aa8cc641d131231acc3470f5c03cb3b07b2e580fb18f8acb3b1dbb72549b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.ERROR: Failed to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.INFO: Trying to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1372,\"provider\":\"hubspot\",\"refreshToken\":\"9aa73948c761da29dce46c177cf9aee1fde483a44169ca38723f9f0597d7a8c4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.ERROR: Failed to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.NOTICE: Repairing HubSpot tokens end {\"total\":3,\"fixed\":0,\"failed\":3} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"jiminny:transcription:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"f73071c7-8696-459f-8aff-e61a7c6b30e6\",\"trace_id\":\"d72fc2ce-5064-4877-b401-10891378e1bc\"}\n[2026-05-28 08:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"720d5c87-3d13-4193-87c9-efb8dc6df7c8\",\"trace_id\":\"a9d9c9fe-db29-44a1-a5f6-1905d48dde90\"}\n[2026-05-28 08:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"jiminny:transcription:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"f73071c7-8696-459f-8aff-e61a7c6b30e6\",\"trace_id\":\"d72fc2ce-5064-4877-b401-10891378e1bc\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Command] Starting polling service {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] Service starting {\"memory_limit\":\"256M\",\"max_execution_time\":\"0\",\"initial_memory_mb\":62.0} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] Acquired polling lock {\"expires_at\":\"2026-05-28T08:32:33.444809Z\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"720d5c87-3d13-4193-87c9-efb8dc6df7c8\",\"trace_id\":\"a9d9c9fe-db29-44a1-a5f6-1905d48dde90\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:35] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:reset-governor\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"c692a62b-3b1a-4ff3-b965-388a7d12f619\",\"trace_id\":\"d1bdfdec-73bd-499f-a31e-b25a864da976\"}\n[2026-05-28 08:30:35] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:reset-governor\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"c692a62b-3b1a-4ff3-b965-388a7d12f619\",\"trace_id\":\"d1bdfdec-73bd-499f-a31e-b25a864da976\"}\n[2026-05-28 08:30:38] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:38] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:38] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:39] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814238,\"provider\":\"twilio-flex\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814239,\"provider\":\"xant\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814240,\"provider\":\"apollo\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814241,\"provider\":\"groove\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814242,\"provider\":\"twilio-video\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814243,\"provider\":\"hubspot\",\"team\":\"hubspot\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:fail-stalled\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"f6d797df-5275-4cf1-8ddd-300c125df8da\",\"trace_id\":\"2b46c31f-aced-4324-a70a-6395f0a72618\"}\n[2026-05-28 08:30:42] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:fail-stalled\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"f6d797df-5275-4cf1-8ddd-300c125df8da\",\"trace_id\":\"2b46c31f-aced-4324-a70a-6395f0a72618\"}\n[2026-05-28 08:30:42] local.WARNING: [Salesforce] Account not connected for user {\"userId\":\"cdf8b554-d951-4758-bc2b-c1b85d1cd0b9\",\"account\":null} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"salesforce\",\"crm_owner\":3,\"team_id\":1} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [CrmOwnerResolver] TeamMember found with active crm connection {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1194,\"provider\":\"twilio-flex\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1194,\"provider\":\"twilio-flex\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SyncActivity] Start {\"import_id\":814238,\"provider\":\"twilio-flex\",\"provider_id\":317,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.NOTICE: [TwilioFlex] Calls import start {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.ALERT: [SyncActivity] Failed {\"import_id\":814238,\"provider\":\"twilio-flex\",\"provider_id\":317,\"team\":\"jiminny\",\"team_id\":1,\"reason\":\"[HTTP 401] Unable to fetch page: Authenticate\",\"file\":\"/home/jiminny/vendor/twilio/sdk/src/Twilio/Page.php\",\"line\":60} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SyncActivity] Start {\"import_id\":814239,\"provider\":\"xant\",\"provider_id\":161,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [Salesforce] Performing query {\"query\":\"\n SELECT Playbooks_Call_Date__c,Playbooks_Call_Recording__c,CreatedDate,TaskSubtype,CallType,CallDurationInSeconds,Id,OwnerId,WhoId,WhatId,Priority,ActivityDate,Subject,Description,Status,Type\n FROM Task\n WHERE IsDeleted = false\n AND LastModifiedDate >= :from\n AND LastModifiedDate <= :to\n ORDER BY LastModifiedDate ASC\n LIMIT :limit\",\"params\":{\"from\":\"2026-05-28T08:14:00Z\",\"to\":\"2026-05-28T08:30:00Z\",\"ownerId\":null,\"subType\":null,\"limit\":5000}} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [Salesforce] Sending request {\"endpoint\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=%0A++++++++++++SELECT+Playbooks_Call_Date__c%2CPlaybooks_Call_Recording__c%2CCreatedDate%2CTaskSubtype%2CCallType%2CCallDurationInSeconds%2CId%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%0A++++++++++++++FROM+Task%0A+++++++++++++WHERE+IsDeleted+%3D+false%0A+++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A+++++++++++++++AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z%0A++++++++++ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000 GET\",\"team_id\":1} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:44] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:44] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:44] local.INFO: [Xant (InsideSales)] No calls found. {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] End {\"import_id\":814239,\"provider\":\"xant\",\"provider_id\":161,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Memory usage {\"import_id\":814239,\"provider\":\"xant\",\"provider_id\":161,\"team\":\"jiminny\",\"team_id\":1,\"memory_usage\":24080216,\"memory_real_usage\":65011712,\"pid\":21708} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Start {\"import_id\":814240,\"provider\":\"apollo\",\"provider_id\":441,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Performing query {\"query\":\"\n SELECT AccountId,CreatedDate,TaskSubtype,CallType,Id,OwnerId,WhoId,WhatId,Priority,ActivityDate,Subject,Description,Status,Type\n FROM Task\n WHERE IsDeleted = false\n AND LastModifiedDate >= :from\n AND LastModifiedDate <= :to\n ORDER BY LastModifiedDate ASC\n LIMIT :limit\",\"params\":{\"from\":\"2026-05-28T08:14:00Z\",\"to\":\"2026-05-28T08:30:00Z\",\"ownerId\":null,\"subType\":null,\"limit\":5000}} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Sending request {\"endpoint\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=%0A++++++++++++SELECT+AccountId%2CCreatedDate%2CTaskSubtype%2CCallType%2CId%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%0A++++++++++++++FROM+Task%0A+++++++++++++WHERE+IsDeleted+%3D+false%0A+++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A+++++++++++++++AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z%0A++++++++++ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000 GET\",\"team_id\":1} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Apollo] No calls found. {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] End {\"import_id\":814240,\"provider\":\"apollo\",\"provider_id\":441,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Memory usage {\"import_id\":814240,\"provider\":\"apollo\",\"provider_id\":441,\"team\":\"jiminny\",\"team_id\":1,\"memory_usage\":24242184,\"memory_real_usage\":65011712,\"pid\":21708} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Start {\"import_id\":814241,\"provider\":\"groove\",\"provider_id\":228,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Performing query {\"query\":\"\n SELECT call_recording_url__c,TaskSubtype,CreatedDate,CallType,CallDurationInSeconds,Id,OwnerId,WhoId,WhatId,Priority,ActivityDate,Subject,Description,Status,Type\n FROM Task\n WHERE IsDeleted = false\n AND LastModifiedDate >= :from\n AND LastModifiedDate <= :to\n ORDER BY LastModifiedDate ASC\n LIMIT :limit\",\"params\":{\"from\":\"2026-05-28T08:14:00Z\",\"to\":\"2026-05-28T08:30:00Z\",\"ownerId\":null,\"subType\":null,\"limit\":5000}} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Sending request {\"endpoint\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=%0A++++++++++++SELECT+call_recording_url__c%2CTaskSubtype%2CCreatedDate%2CCallType%2CCallDurationInSeconds%2CId%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%0A++++++++++++++FROM+Task%0A+++++++++++++WHERE+IsDeleted+%3D+false%0A+++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A+++++++++++++++AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z%0A++++++++++ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000 GET\",\"team_id\":1} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"b2b37795-cfa8-472a-b681-322ce27c0e08\",\"trace_id\":\"605e54f2-d4f9-4683-b3fd-6c1c23e691b7\"}\n[2026-05-28 08:30:44] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"b2b37795-cfa8-472a-b681-322ce27c0e08\",\"trace_id\":\"605e54f2-d4f9-4683-b3fd-6c1c23e691b7\"}\n[2026-05-28 08:30:44] local.ERROR: [Salesforce] Request exception [400] \nSELECT call_recording_url__c,TaskSubtype\n ^\nERROR at Row:1:Column:8\nNo such column 'call_recording_url__c' on entity 'Task'. If you are attempting to use a custom field, be sure to append the '__c' after the custom field name. Please reference your WSDL or the describe call for the appropriate names. {\"url\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=%0A++++++++++++SELECT+call_recording_url__c%2CTaskSubtype%2CCreatedDate%2CCallType%2CCallDurationInSeconds%2CId%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%0A++++++++++++++FROM+Task%0A+++++++++++++WHERE+IsDeleted+%3D+false%0A+++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A+++++++++++++++AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z%0A++++++++++ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000\",\"data\":{\"headers\":{\"Authorization\":\"Bearer 00D2g0000008hH4!AQEAQHWUK6nshi8dSCX9CJphxkVivcv_TK98TLOckVy4i0Z1gQfAoRRuH2LVwDXDkbTPs80wvQjczjAlOz0UEtbHoORBLi2u\"}},\"response\":{\"GuzzleHttp\\\\Psr7\\\\Stream\":\"[{\\\"message\\\":\\\"\\\\nSELECT call_recording_url__c,TaskSubtype\\\\n ^\\\\nERROR at Row:1:Column:8\\\\nNo such column 'call_recording_url__c' on entity 'Task'. If you are attempting to use a custom field, be sure to append the '__c' after the custom field name. Please reference your WSDL or the describe call for the appropriate names.\\\",\\\"errorCode\\\":\\\"INVALID_FIELD\\\"}]\"},\"fields\":[]} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.ALERT: [SyncActivity] Failed {\"import_id\":814241,\"provider\":\"groove\",\"provider_id\":228,\"team\":\"jiminny\",\"team_id\":1,\"reason\":\"\nSELECT call_recording_url__c,TaskSubtype\n ^\nERROR at Row:1:Column:8\nNo such column 'call_recording_url__c' on entity 'Task'. If you are attempting to use a custom field, be sure to append the '__c' after the custom field name. Please reference your WSDL or the describe call for the appropriate names.\",\"file\":\"/home/jiminny/app/Services/Crm/Salesforce/Client.php\",\"line\":564} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Start {\"import_id\":814242,\"provider\":\"twilio-video\",\"provider_id\":243,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Performing query {\"query\":\"SELECT Id,OwnerId,WhoId,WhatId,Priority,ActivityDate,Subject,Description,Status,Type,twilio_call_sid__c,Lead_UUID__c,Opportunity__c\n FROM Task\n WHERE Type = 'Video'\n AND isClosed = true\n AND IsDeleted = false\n AND LastModifiedDate >= :from\n AND twilio_call_sid__c != NULL AND LastModifiedDate <= :to ORDER BY LastModifiedDate ASC\n LIMIT :limit\",\"params\":{\"from\":\"2026-05-28T08:14:00Z\",\"to\":\"2026-05-28T08:30:00Z\",\"ownerId\":null,\"subType\":null,\"limit\":5000}} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Sending request {\"endpoint\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=SELECT+Id%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%2Ctwilio_call_sid__c%2CLead_UUID__c%2COpportunity__c%0A++++++++++++++FROM+Task%0A++++++++++++WHERE+Type+%3D+%27Video%27%0A++++++++++++++AND+isClosed+%3D+true%0A++++++++++++++AND+IsDeleted+%3D+false%0A++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A++++++++++++++AND+twilio_call_sid__c+%21%3D+NULL+AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z+ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000 GET\",\"team_id\":1} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [Twilio Video] No calls found. {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] End {\"import_id\":814242,\"provider\":\"twilio-video\",\"provider_id\":243,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] Memory usage {\"import_id\":814242,\"provider\":\"twilio-video\",\"provider_id\":243,\"team\":\"jiminny\",\"team_id\":1,\"memory_usage\":24634032,\"memory_real_usage\":65011712,\"pid\":21708} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":89,\"team_id\":2} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":408,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":408,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] Start {\"import_id\":814243,\"provider\":\"hubspot\",\"provider_id\":31,\"team\":\"hubspot\",\"team_id\":2} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [HubSpot] Search calls for period {\"from\":\"2026-05-28 08:14:00\",\"to\":\"2026-05-28 08:30:00\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] End {\"import_id\":814243,\"provider\":\"hubspot\",\"provider_id\":31,\"team\":\"hubspot\",\"team_id\":2} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] Memory usage {\"import_id\":814243,\"provider\":\"hubspot\",\"provider_id\":31,\"team\":\"hubspot\",\"team_id\":2,\"memory_usage\":24947696,\"memory_real_usage\":65011712,\"pid\":21708} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:46] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"nudges:send\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"f3e257b6-82bb-440c-bf76-855ac528e4e8\",\"trace_id\":\"f8a31218-7290-45ac-8fe1-ffb1b8527521\"}\n[2026-05-28 08:30:46] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"nudges:send\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"f3e257b6-82bb-440c-bf76-855ac528e4e8\",\"trace_id\":\"f8a31218-7290-45ac-8fe1-ffb1b8527521\"}\n[2026-05-28 08:30:50] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"jiminny:playlists:normalize-sort\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"a64b1836-79a1-41da-a4b0-bc0a9703a94b\",\"trace_id\":\"c53faedc-a7a7-41b7-8e51-e84dc2755d79\"}\n[2026-05-28 08:30:50] local.INFO: [Jiminny\\Component\\Playlist\\Command\\NormalizeSortCommand::handle] starting. {\"playlists\":[]} {\"correlation_id\":\"a64b1836-79a1-41da-a4b0-bc0a9703a94b\",\"trace_id\":\"c53faedc-a7a7-41b7-8e51-e84dc2755d79\"}\n[2026-05-28 08:30:50] local.INFO: [Jiminny\\Component\\Playlist\\Command\\NormalizeSortCommand::handle] finished. {\"normalizedPlaylists\":[],\"deletedPlaylists\":[]} {\"correlation_id\":\"a64b1836-79a1-41da-a4b0-bc0a9703a94b\",\"trace_id\":\"c53faedc-a7a7-41b7-8e51-e84dc2755d79\"}\n[2026-05-28 08:30:50] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"jiminny:playlists:normalize-sort\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"a64b1836-79a1-41da-a4b0-bc0a9703a94b\",\"trace_id\":\"c53faedc-a7a7-41b7-8e51-e84dc2755d79\"}\n[2026-05-28 08:30:59] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:59] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:59] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"41db30ba-33c5-46f1-b8bd-5d9e86a70d12\",\"trace_id\":\"a5e2028d-ca41-4ba1-9ddd-a246f83ef4cc\"}\n[2026-05-28 08:31:07] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"41db30ba-33c5-46f1-b8bd-5d9e86a70d12\",\"trace_id\":\"a5e2028d-ca41-4ba1-9ddd-a246f83ef4cc\"}\n[2026-05-28 08:31:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"41db30ba-33c5-46f1-b8bd-5d9e86a70d12\",\"trace_id\":\"a5e2028d-ca41-4ba1-9ddd-a246f83ef4cc\"}\n[2026-05-28 08:31:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"f6ed0a05-caa1-4cb6-ae83-63f44ae4e0d6\",\"trace_id\":\"16cd898d-57a1-4b74-90d1-f9223bbd8d7a\"}\n[2026-05-28 08:31:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"f6ed0a05-caa1-4cb6-ae83-63f44ae4e0d6\",\"trace_id\":\"16cd898d-57a1-4b74-90d1-f9223bbd8d7a\"}\n[2026-05-28 08:31:15] local.NOTICE: Monitoring start {\"correlation_id\":\"cdf384ea-4f59-4411-8ebf-efc299e4a1c8\",\"trace_id\":\"b069d3c8-2f77-4698-bd53-97de373652e8\"}\n[2026-05-28 08:31:15] local.NOTICE: Monitoring end {\"correlation_id\":\"cdf384ea-4f59-4411-8ebf-efc299e4a1c8\",\"trace_id\":\"b069d3c8-2f77-4698-bd53-97de373652e8\"}\n[2026-05-28 08:31:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"940a264b-4aee-40a0-a527-e101ea555a38\",\"trace_id\":\"cd9169ad-4c1e-452d-b7cb-66005aae4dc8\"}\n[2026-05-28 08:31:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"940a264b-4aee-40a0-a527-e101ea555a38\",\"trace_id\":\"cd9169ad-4c1e-452d-b7cb-66005aae4dc8\"}\n[2026-05-28 08:31:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"b798f381-71f2-4c51-a135-f91f09330cfd\",\"trace_id\":\"b44ed325-23f7-4f8b-a447-4c8d0ee99d01\"}\n[2026-05-28 08:31:23] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"b798f381-71f2-4c51-a135-f91f09330cfd\",\"trace_id\":\"b44ed325-23f7-4f8b-a447-4c8d0ee99d01\"}\n[2026-05-28 08:31:24] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"b798f381-71f2-4c51-a135-f91f09330cfd\",\"trace_id\":\"b44ed325-23f7-4f8b-a447-4c8d0ee99d01\"}\n[2026-05-28 08:31:24] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"b798f381-71f2-4c51-a135-f91f09330cfd\",\"trace_id\":\"b44ed325-23f7-4f8b-a447-4c8d0ee99d01\"}\n[2026-05-28 08:31:27] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"2d631328-f2b9-44f3-83d3-613b7b9b9ddc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:27] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"2d631328-f2b9-44f3-83d3-613b7b9b9ddc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"usage\":22563136,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [HubSpot] Syncing opportunities using strategy: lastModified {\"team\":2} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.4,\"average_seconds_per_request\":0.4} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [HubSpot] Synced opportunities {\"team\":2,\"strategies\":\"lastModified\",\"sync_count\":0,\"total\":0,\"last_synced_id\":null,\"duration_ms\":432.6} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"provider\":\"hubspot\",\"status\":\"completed\",\"duration_ms\":543.02,\"usage\":22983640,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"usage\":22961848,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"2ac0447f-3c8c-4ce0-baeb-b63ddb76fa9b\",\"account\":null} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":130,\"team_id\":42} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":23.85,\"usage\":23024000,\"real_usage\":65011712,\"pid\":21703,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"usage\":22984760,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"33e34a7a-1c02-4f04-87ac-22c3a385e6e3\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":306,\"sociable_id\":109,\"provider_user_id\":\"11348452\",\"expires\":1701077403,\"refresh_token_expires\":null,\"provider\":\"hubspot\",\"state\":\"full-refresh\",\"auth_scope\":null,\"retry_after\":null,\"created_at\":\"2020-09-01 16:59:04\",\"updated_at\":\"2023-11-27 09:30:03\"}}} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":109,\"team_id\":29} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":14.98,\"usage\":23047624,\"real_usage\":65011712,\"pid\":21703,\"reason\":\"Your HubSpot account has become disconnected. Please login to Jiminny to reconnect.\"} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal Polling] Service ending {\"runtime_seconds\":56,\"total_cycles\":5,\"files_downloaded\":0,\"empty_files\":0,\"other_portal_skipped\":0,\"total_events\":0,\"events_per_file\":0,\"avg_api_ms\":192.1,\"avg_download_ms\":0.0,\"avg_transform_ms\":0.0,\"avg_process_ms\":0.0,\"peak_memory_mb\":99.88} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal Polling] Released polling lock {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"usage\":23005136,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"71e3aac5-fb66-47c5-a236-2d051ae3e319\",\"account\":null} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":256,\"team_id\":49} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":34.51,\"usage\":23021248,\"real_usage\":65011712,\"pid\":21703,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:32:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"35f98b1b-7b16-4e79-a420-7e9818097d24\",\"trace_id\":\"d66deb58-fa13-486f-a866-2cac402dc589\"}\n[2026-05-28 08:32:06] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"35f98b1b-7b16-4e79-a420-7e9818097d24\",\"trace_id\":\"d66deb58-fa13-486f-a866-2cac402dc589\"}\n[2026-05-28 08:32:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"35f98b1b-7b16-4e79-a420-7e9818097d24\",\"trace_id\":\"d66deb58-fa13-486f-a866-2cac402dc589\"}\n[2026-05-28 08:32:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"bc6784c1-c46f-4295-be09-87334f4baa39\",\"trace_id\":\"74b00236-4ed0-4464-8b07-99c328ab6461\"}\n[2026-05-28 08:32:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"bc6784c1-c46f-4295-be09-87334f4baa39\",\"trace_id\":\"74b00236-4ed0-4464-8b07-99c328ab6461\"}\n[2026-05-28 08:32:11] local.NOTICE: Monitoring start {\"correlation_id\":\"caf4d1dd-2a52-40f5-834a-f9148f642e83\",\"trace_id\":\"1312bdcc-7e8b-480a-a935-2433fb79dc70\"}\n[2026-05-28 08:32:11] local.NOTICE: Monitoring end {\"correlation_id\":\"caf4d1dd-2a52-40f5-834a-f9148f642e83\",\"trace_id\":\"1312bdcc-7e8b-480a-a935-2433fb79dc70\"}\n[2026-05-28 08:32:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"64d86889-1f0d-4f7d-a1ac-6f56e58e775e\",\"trace_id\":\"b184d66b-49f8-40ec-afbe-2e76e9c7d952\"}\n[2026-05-28 08:32:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"64d86889-1f0d-4f7d-a1ac-6f56e58e775e\",\"trace_id\":\"b184d66b-49f8-40ec-afbe-2e76e9c7d952\"}\n[2026-05-28 08:32:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"8e6dd4bc-4f44-4fb2-b2ba-9e2f385996ef\",\"trace_id\":\"7767e0ca-37a3-43a5-972e-ea9a1bedea2f\"}\n[2026-05-28 08:32:20] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"8e6dd4bc-4f44-4fb2-b2ba-9e2f385996ef\",\"trace_id\":\"7767e0ca-37a3-43a5-972e-ea9a1bedea2f\"}\n[2026-05-28 08:32:20] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"8e6dd4bc-4f44-4fb2-b2ba-9e2f385996ef\",\"trace_id\":\"7767e0ca-37a3-43a5-972e-ea9a1bedea2f\"}\n[2026-05-28 08:32:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"8e6dd4bc-4f44-4fb2-b2ba-9e2f385996ef\",\"trace_id\":\"7767e0ca-37a3-43a5-972e-ea9a1bedea2f\"}\n[2026-05-28 08:32:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"6750ab25-6dff-4e7b-9f6e-bc7d1fc4221a\",\"trace_id\":\"3db6ce9b-167d-4214-a32c-67c611aa2bbe\"}\n[2026-05-28 08:32:22] local.INFO: Running conference:monitor:count command for activities in (2026-05-28 08:30:00, 2026-05-28 08:32:00] {\"correlation_id\":\"6750ab25-6dff-4e7b-9f6e-bc7d1fc4221a\",\"trace_id\":\"3db6ce9b-167d-4214-a32c-67c611aa2bbe\"}\n[2026-05-28 08:32:22] local.INFO: [conference:monitor:count] No activities found in (2026-05-28 08:30:00, 2026-05-28 08:32:00] {\"correlation_id\":\"6750ab25-6dff-4e7b-9f6e-bc7d1fc4221a\",\"trace_id\":\"3db6ce9b-167d-4214-a32c-67c611aa2bbe\"}\n[2026-05-28 08:32:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"6750ab25-6dff-4e7b-9f6e-bc7d1fc4221a\",\"trace_id\":\"3db6ce9b-167d-4214-a32c-67c611aa2bbe\"}\n[2026-05-28 08:32:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"04510c2c-638c-4687-81d7-b12e76f41df3\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}\n[2026-05-28 08:32:23] local.INFO: [EmailSchedule] STARTING batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"04510c2c-638c-4687-81d7-b12e76f41df3\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}\n[2026-05-28 08:32:23] local.INFO: [EmailSchedule] FINISHED batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"04510c2c-638c-4687-81d7-b12e76f41df3\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}\n[2026-05-28 08:32:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"04510c2c-638c-4687-81d7-b12e76f41df3\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}\n[2026-05-28 08:32:25] local.INFO: [Jiminny\\Jobs\\Mailbox\\CreateBatches] processed 1 inboxes and created 0 batches {\"userId\":null,\"batchSize\":30,\"maxBatches\":1000} {\"correlation_id\":\"e60597ef-aca8-4bda-bb90-18f01e96874d\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}","depth":4,"bounds":{"left":0.4331782,"top":0.09736632,"width":0.5668218,"height":0.90263367},"on_screen":true,"value":"[2026-05-28 08:28:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"73199e23-a066-42ba-b189-2802e0869a44\",\"trace_id\":\"e53672c2-0f50-409d-af25-84ab485c505d\"}\n[2026-05-28 08:28:04] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"73199e23-a066-42ba-b189-2802e0869a44\",\"trace_id\":\"e53672c2-0f50-409d-af25-84ab485c505d\"}\n[2026-05-28 08:28:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"73199e23-a066-42ba-b189-2802e0869a44\",\"trace_id\":\"e53672c2-0f50-409d-af25-84ab485c505d\"}\n[2026-05-28 08:28:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"741b2c4e-6a44-4c46-b9fb-fce017aef225\",\"trace_id\":\"804dc547-eb25-4b32-8d0f-c87019773085\"}\n[2026-05-28 08:28:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"741b2c4e-6a44-4c46-b9fb-fce017aef225\",\"trace_id\":\"804dc547-eb25-4b32-8d0f-c87019773085\"}\n[2026-05-28 08:28:09] local.NOTICE: Monitoring start {\"correlation_id\":\"8ae5c131-edd9-463d-8161-875f4d34320f\",\"trace_id\":\"1b6420c8-ef4e-4566-81b2-688696064648\"}\n[2026-05-28 08:28:09] local.NOTICE: Monitoring end {\"correlation_id\":\"8ae5c131-edd9-463d-8161-875f4d34320f\",\"trace_id\":\"1b6420c8-ef4e-4566-81b2-688696064648\"}\n[2026-05-28 08:28:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"6f5390d3-abe7-4e56-a662-aeed1098941b\",\"trace_id\":\"b57dc2df-2f4d-4d3b-b09a-aa6e61205d5e\"}\n[2026-05-28 08:28:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"6f5390d3-abe7-4e56-a662-aeed1098941b\",\"trace_id\":\"b57dc2df-2f4d-4d3b-b09a-aa6e61205d5e\"}\n[2026-05-28 08:28:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"ba694158-ea28-4ac1-b134-83ac485146e0\",\"trace_id\":\"83a26b74-baa5-407e-9fc2-2b49d65b1c77\"}\n[2026-05-28 08:28:12] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"ba694158-ea28-4ac1-b134-83ac485146e0\",\"trace_id\":\"83a26b74-baa5-407e-9fc2-2b49d65b1c77\"}\n[2026-05-28 08:28:12] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"ba694158-ea28-4ac1-b134-83ac485146e0\",\"trace_id\":\"83a26b74-baa5-407e-9fc2-2b49d65b1c77\"}\n[2026-05-28 08:28:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"ba694158-ea28-4ac1-b134-83ac485146e0\",\"trace_id\":\"83a26b74-baa5-407e-9fc2-2b49d65b1c77\"}\n[2026-05-28 08:28:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"b79833c7-3eab-4eb7-98bb-42359039b8fb\",\"trace_id\":\"a8e159bc-867d-40af-bf7d-1228cf6d4f16\"}\n[2026-05-28 08:28:14] local.INFO: Running conference:monitor:count command for activities in (2026-05-28 08:26:00, 2026-05-28 08:28:00] {\"correlation_id\":\"b79833c7-3eab-4eb7-98bb-42359039b8fb\",\"trace_id\":\"a8e159bc-867d-40af-bf7d-1228cf6d4f16\"}\n[2026-05-28 08:28:14] local.INFO: [conference:monitor:count] No activities found in (2026-05-28 08:26:00, 2026-05-28 08:28:00] {\"correlation_id\":\"b79833c7-3eab-4eb7-98bb-42359039b8fb\",\"trace_id\":\"a8e159bc-867d-40af-bf7d-1228cf6d4f16\"}\n[2026-05-28 08:28:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"b79833c7-3eab-4eb7-98bb-42359039b8fb\",\"trace_id\":\"a8e159bc-867d-40af-bf7d-1228cf6d4f16\"}\n[2026-05-28 08:28:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"d51071d5-ead0-45f0-a07e-e3234074f884\",\"trace_id\":\"77173d9f-596f-405f-ae55-ba117b66455d\"}\n[2026-05-28 08:28:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"calendar:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.NOTICE: Calendar sync start {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"d51071d5-ead0-45f0-a07e-e3234074f884\",\"trace_id\":\"77173d9f-596f-405f-ae55-ba117b66455d\"}\n[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1393,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1393,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1393,\"provider\":\"google\",\"refreshToken\":\"5aa7e2d96b53201cd16fca5d2e4ef3ad03320971fc064781d18aee3ae7b99fbf\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1393,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1393,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1387,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1387,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1387,\"provider\":\"google\",\"refreshToken\":\"8157ac6de94842937194009e9c50e459253600f799dacf6a40755ffdbeb5bba6\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1387,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1387,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1348,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1348,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1348,\"provider\":\"google\",\"refreshToken\":\"9e7d13d3032d0cb1b79d8e95aef01383e8e91eb52ff8ee960c8a0b6b95cd8c73\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1348,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1348,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1361,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1361,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1361,\"provider\":\"google\",\"refreshToken\":\"6c843da199c2b9907445329304fcc4ec5057a4ee748d8299641764395c08e1fd\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1361,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1361,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1310,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1310,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1310,\"provider\":\"google\",\"refreshToken\":\"e34818922c2830a660813a63f6169a4a9a992ae2cccd7dc8dd7796cfdb470ef1\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1310,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1310,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1333,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1333,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1333,\"provider\":\"google\",\"refreshToken\":\"6c902986546d8e8da1dc539b046cdc1d458f519acc972e5b5f1d6a1a295165e0\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1333,\"provider\":\"google\",\"responseBody\":{\"error\":\"unauthorized_client\",\"error_description\":\"Unauthorized\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1333,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1368,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1368,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1368,\"provider\":\"google\",\"refreshToken\":\"d2f128898ff8543bd16b69cfae37896ab85119b0f5ed2b431d739593bb600333\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1368,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1368,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1365,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1365,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1365,\"provider\":\"google\",\"refreshToken\":\"7676e4a9afcd082b413248ab5ec6e487021fec6a9bdf315860a59cefad9caad8\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1365,\"provider\":\"google\",\"responseBody\":{\"error\":\"unauthorized_client\",\"error_description\":\"Unauthorized\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1365,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1364,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1364,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1364,\"provider\":\"google\",\"refreshToken\":\"dd5882ebce76e645292ce33ae74238abbb77c0a4ecc6a2bfe723cad82e72ba8e\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1364,\"provider\":\"google\",\"responseBody\":{\"error\":\"unauthorized_client\",\"error_description\":\"Unauthorized\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1364,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1370,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1370,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1370,\"provider\":\"office\",\"refreshToken\":\"b7ee8035306d0043cea6e00e7c4fe14f745e44074a1194db62a31cdf8b70af3e\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1370,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 41d8db5c-a91f-41a6-9b5c-22a6c99b9100 Correlation ID: 70bc0a6f-1565-4e74-94dc-419d94108fa9 Timestamp: 2026-05-28 08:28:18Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:18Z\\\",\\\"trace_id\\\":\\\"41d8db5c-a91f-41a6-9b5c-22a6c99b9100\\\",\\\"correlation_id\\\":\\\"70bc0a6f-1565-4e74-94dc-419d94108fa9\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1370,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1202,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1202,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1202,\"provider\":\"office\",\"refreshToken\":\"b458799ccc29b21a6e2eb5260fdb63e49ccba21bf942a3973fb63799bd7f0afe\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1202,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: d3d14dfc-1b70-40c4-b9db-fab12f748300 Correlation ID: 4c5f746c-8366-44c1-8733-6877607826db Timestamp: 2026-05-28 08:28:19Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:19Z\\\",\\\"trace_id\\\":\\\"d3d14dfc-1b70-40c4-b9db-fab12f748300\\\",\\\"correlation_id\\\":\\\"4c5f746c-8366-44c1-8733-6877607826db\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1202,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: Calendar sync job dispatched {\"calendar_id\":501} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1300,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1300,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1300,\"provider\":\"google\",\"refreshToken\":\"4b811db0725fd9602a95943519a7da935e2a5065da7d9ebfcb170752e3e1ddb8\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1300,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1300,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1409,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1409,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1409,\"provider\":\"google\",\"refreshToken\":\"e2a3f2d06894894eed1ee87d9db1ace77d4d42ee6e1288a8940ad2c10333b0c4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1409,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1409,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1352,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1352,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1352,\"provider\":\"google\",\"refreshToken\":\"dd4b16b00fdc1216da6b717c02338c073636e29162826b2de6db3f064fc029eb\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1352,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1352,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1296,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1296,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1296,\"provider\":\"office\",\"refreshToken\":\"011ae723c9d800c674e0b4be76f49fc046dac7d501b66c59ef0d9549cfa56ae5\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [Calendar] Processing sync {\"calendarId\":\"a33076c1-8d97-431a-99f0-85c9524e118b\",\"from\":null,\"to\":null,\"delta\":\"CIiFh8TP44kDEIiFh8TP44kDGAUgkZvkzgIokZvkzgI=\",\"last_sync\":\"2024-12-09 07:12:53\",\"dateMode\":\"daily\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"integration-app\",\"crm_owner\":1695,\"team_id\":3143} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1296,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: dd83a147-95bc-407c-8c9b-3c14e7cb7d00 Correlation ID: bb16bae3-b3c4-467e-bd95-4e7ab85364c9 Timestamp: 2026-05-28 08:28:20Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:20Z\\\",\\\"trace_id\\\":\\\"dd83a147-95bc-407c-8c9b-3c14e7cb7d00\\\",\\\"correlation_id\\\":\\\"bb16bae3-b3c4-467e-bd95-4e7ab85364c9\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1296,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":391,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":391,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":391,\"provider\":\"office\",\"refreshToken\":\"00045eebae0f39b34887c6d53f92ae78064f7145e1f4b67754aebd03cfb2d881\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [Google Calendar] Failed to watch channel for calendar {\"calendarId\":\"a33076c1-8d97-431a-99f0-85c9524e118b\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.WARNING: [Calendar] Sync failed {\"calendarId\":\"a33076c1-8d97-431a-99f0-85c9524e118b\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":391,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 587224ad-f597-4371-b2ba-00fcd2da1b00 Correlation ID: 4e752610-95b1-4606-847f-68e00f90be0a Timestamp: 2026-05-28 08:28:21Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:21Z\\\",\\\"trace_id\\\":\\\"587224ad-f597-4371-b2ba-00fcd2da1b00\\\",\\\"correlation_id\\\":\\\"4e752610-95b1-4606-847f-68e00f90be0a\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":391,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1271,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1271,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1271,\"provider\":\"office\",\"refreshToken\":\"118cde2c06993147b07ccaec4cbcd5026a819dea6c71081166a492933e392afb\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1271,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: dd8bf2a7-bc49-43d7-a487-892c51e27600 Correlation ID: 51e3eb6c-c47e-4dd7-91aa-e734fe5b65cf Timestamp: 2026-05-28 08:28:21Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:21Z\\\",\\\"trace_id\\\":\\\"dd8bf2a7-bc49-43d7-a487-892c51e27600\\\",\\\"correlation_id\\\":\\\"51e3eb6c-c47e-4dd7-91aa-e734fe5b65cf\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1271,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1351,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1351,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1351,\"provider\":\"google\",\"refreshToken\":\"4271d15b9e60a606439caddc68337f783e472c85b03dacff14d1b6dfded9051c\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1351,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1351,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1366,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1366,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1366,\"provider\":\"google\",\"refreshToken\":\"ae21385059b2eebfd43f68aecd56eccd702a1aabb6598f1f7ab594ed8af491b4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1366,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1366,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: Calendar sync job dispatched {\"calendar_id\":378} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: Calendar sync job dispatched {\"calendar_id\":504} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.NOTICE: Calendar sync end {\"retrieved_calendars\":31,\"processed_calendars\":3} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"calendar:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [Calendar] Processing sync {\"calendarId\":\"2676cb6d-f86c-427e-bf78-591e388e3c1e\",\"from\":null,\"to\":null,\"delta\":\"CJ_x49O3jpIDEJ_x49O3jpIDGAUgw67KlwMow67KlwM=\",\"last_sync\":\"2026-01-19 07:48:40\",\"dateMode\":\"daily\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.WARNING: [Pipedrive] Account not connected for user {\"userId\":\"e6538737-e7b4-455f-a37a-3e79b665a220\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":1116,\"sociable_id\":241,\"provider_user_id\":\"19555731\",\"expires\":1779091997,\"refresh_token_expires\":null,\"provider\":\"pipedrive\",\"state\":\"full-refresh\",\"auth_scope\":\"base,deals:full,activities:full,contacts:full,search:read\",\"retry_after\":null,\"created_at\":\"2023-09-08 09:44:29\",\"updated_at\":\"2026-05-18 08:13:32\"}}} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"pipedrive\",\"crm_owner\":241,\"team_id\":19} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"pipedrive\",\"team_id\":19} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"pipedrive\",\"team_id\":19} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.WARNING: [Calendar] CRM disconnected for user so events will not be matched {\"provider\":\"pipedrive\",\"user_id\":241,\"message\":\"Your Pipedrive account has become disconnected. Please login to Jiminny to reconnect.\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [Google Calendar] Failed to watch channel for calendar {\"calendarId\":\"2676cb6d-f86c-427e-bf78-591e388e3c1e\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.WARNING: [Calendar] Sync failed {\"calendarId\":\"2676cb6d-f86c-427e-bf78-591e388e3c1e\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [Calendar] Processing sync {\"calendarId\":\"9e8b1a2c-1a8f-42bd-b161-810fc0baf540\",\"from\":null,\"to\":null,\"delta\":\"R0usmcdvmMuZCBYV0hguCBhf4uKqyU9_gdNd-le_nqqau95XAUmZwlIAy2uwtCf5sA67w6NIiDvawUSmVjpTzZO-RsxLdeS-g8Kxy6ODZQxAxafq8AJNx0hJV7T291NUvfaPYqLMv-3je3IdhAPUtXQXkHtYaBAlX_DDBxwc3zYoVVQ8iM9mQkBykdA3sh-KVYPyzi7nK4cZg5Jzpu9tHA.UA7urx3pJyhUhdo_16STIbSNXUrF-qeQVIis9stVUeY\",\"last_sync\":\"2026-05-28 07:44:06\",\"dateMode\":\"daily\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":89,\"team_id\":2} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [MS Office Calendar] Skipping delta sync for daily mode {\"calendarId\":\"9e8b1a2c-1a8f-42bd-b161-810fc0baf540\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:29:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"86a65904-a9f8-43c9-b0c3-1e9c8b4b9541\",\"trace_id\":\"800b02ff-3553-46a3-a8c6-c12324a1ce53\"}\n[2026-05-28 08:29:05] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"86a65904-a9f8-43c9-b0c3-1e9c8b4b9541\",\"trace_id\":\"800b02ff-3553-46a3-a8c6-c12324a1ce53\"}\n[2026-05-28 08:29:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"86a65904-a9f8-43c9-b0c3-1e9c8b4b9541\",\"trace_id\":\"800b02ff-3553-46a3-a8c6-c12324a1ce53\"}\n[2026-05-28 08:29:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"e5162656-5b49-4857-9917-f0cf3ddffe27\",\"trace_id\":\"a3a53cc5-596d-474c-b9c4-f6c5f7ebdfd0\"}\n[2026-05-28 08:29:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"e5162656-5b49-4857-9917-f0cf3ddffe27\",\"trace_id\":\"a3a53cc5-596d-474c-b9c4-f6c5f7ebdfd0\"}\n[2026-05-28 08:29:09] local.NOTICE: Monitoring start {\"correlation_id\":\"f559463e-0c12-46df-8b53-0c50cf4aa3eb\",\"trace_id\":\"5a09aee9-5f75-4bfa-93e4-df0ff76f2326\"}\n[2026-05-28 08:29:09] local.NOTICE: Monitoring end {\"correlation_id\":\"f559463e-0c12-46df-8b53-0c50cf4aa3eb\",\"trace_id\":\"5a09aee9-5f75-4bfa-93e4-df0ff76f2326\"}\n[2026-05-28 08:29:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"9b1cc2f1-0c8a-4aa0-a9e8-57ac879839e4\",\"trace_id\":\"d69dd133-b5f0-4568-81ef-9cce3d1c5c9e\"}\n[2026-05-28 08:29:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"9b1cc2f1-0c8a-4aa0-a9e8-57ac879839e4\",\"trace_id\":\"d69dd133-b5f0-4568-81ef-9cce3d1c5c9e\"}\n[2026-05-28 08:29:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"87e10603-9e6f-4d71-97ab-5ba67103e5fd\",\"trace_id\":\"0aae0afb-779f-4999-892d-0188e14b3dcb\"}\n[2026-05-28 08:29:12] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"87e10603-9e6f-4d71-97ab-5ba67103e5fd\",\"trace_id\":\"0aae0afb-779f-4999-892d-0188e14b3dcb\"}\n[2026-05-28 08:29:12] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"87e10603-9e6f-4d71-97ab-5ba67103e5fd\",\"trace_id\":\"0aae0afb-779f-4999-892d-0188e14b3dcb\"}\n[2026-05-28 08:29:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"87e10603-9e6f-4d71-97ab-5ba67103e5fd\",\"trace_id\":\"0aae0afb-779f-4999-892d-0188e14b3dcb\"}\n[2026-05-28 08:30:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"200b132b-d8db-4010-b968-fe5e3fcc42f1\",\"trace_id\":\"7457715a-3b9d-4c35-a499-455c83e925ab\"}\n[2026-05-28 08:30:04] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"200b132b-d8db-4010-b968-fe5e3fcc42f1\",\"trace_id\":\"7457715a-3b9d-4c35-a499-455c83e925ab\"}\n[2026-05-28 08:30:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"200b132b-d8db-4010-b968-fe5e3fcc42f1\",\"trace_id\":\"7457715a-3b9d-4c35-a499-455c83e925ab\"}\n[2026-05-28 08:30:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"a94ef973-dee7-4bdf-99aa-9ff06f5a5561\",\"trace_id\":\"4e37013f-2993-4c71-87d9-560f8f429d27\"}\n[2026-05-28 08:30:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"a94ef973-dee7-4bdf-99aa-9ff06f5a5561\",\"trace_id\":\"4e37013f-2993-4c71-87d9-560f8f429d27\"}\n[2026-05-28 08:30:07] local.NOTICE: Monitoring start {\"correlation_id\":\"691e7103-784d-4b4a-8036-f3c624a186db\",\"trace_id\":\"991dd947-ed80-4080-8769-8ee7efc4e6a4\"}\n[2026-05-28 08:30:07] local.NOTICE: Monitoring end {\"correlation_id\":\"691e7103-784d-4b4a-8036-f3c624a186db\",\"trace_id\":\"991dd947-ed80-4080-8769-8ee7efc4e6a4\"}\n[2026-05-28 08:30:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"00cf8914-d440-4826-a079-ee4586e76c62\",\"trace_id\":\"d77009ee-8d7b-44ae-bb21-2080b6d48c6c\"}\n[2026-05-28 08:30:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"00cf8914-d440-4826-a079-ee4586e76c62\",\"trace_id\":\"d77009ee-8d7b-44ae-bb21-2080b6d48c6c\"}\n[2026-05-28 08:30:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"7c9550d0-42ed-4b1d-b5b3-7dca67f743ec\",\"trace_id\":\"84177853-9530-4b1e-bde6-3dc0c71883ee\"}\n[2026-05-28 08:30:10] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"7c9550d0-42ed-4b1d-b5b3-7dca67f743ec\",\"trace_id\":\"84177853-9530-4b1e-bde6-3dc0c71883ee\"}\n[2026-05-28 08:30:10] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"7c9550d0-42ed-4b1d-b5b3-7dca67f743ec\",\"trace_id\":\"84177853-9530-4b1e-bde6-3dc0c71883ee\"}\n[2026-05-28 08:30:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"7c9550d0-42ed-4b1d-b5b3-7dca67f743ec\",\"trace_id\":\"84177853-9530-4b1e-bde6-3dc0c71883ee\"}\n[2026-05-28 08:30:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"85cc6c92-262b-45c5-bbcc-4a084137fde3\",\"trace_id\":\"058bc9a3-67af-49b6-a87c-8a0a0bc0c47a\"}\n[2026-05-28 08:30:12] local.INFO: Running conference:monitor:count command for activities in (2026-05-28 08:28:00, 2026-05-28 08:30:00] {\"correlation_id\":\"85cc6c92-262b-45c5-bbcc-4a084137fde3\",\"trace_id\":\"058bc9a3-67af-49b6-a87c-8a0a0bc0c47a\"}\n[2026-05-28 08:30:12] local.INFO: [conference:monitor:count] No activities found in (2026-05-28 08:28:00, 2026-05-28 08:30:00] {\"correlation_id\":\"85cc6c92-262b-45c5-bbcc-4a084137fde3\",\"trace_id\":\"058bc9a3-67af-49b6-a87c-8a0a0bc0c47a\"}\n[2026-05-28 08:30:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"85cc6c92-262b-45c5-bbcc-4a084137fde3\",\"trace_id\":\"058bc9a3-67af-49b6-a87c-8a0a0bc0c47a\"}\n[2026-05-28 08:30:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"5083d024-d669-4c6a-bde3-ce084d6a628c\",\"trace_id\":\"83110e1f-4309-4f4a-b8bb-eab5c0ec081e\"}\n[2026-05-28 08:30:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"5083d024-d669-4c6a-bde3-ce084d6a628c\",\"trace_id\":\"83110e1f-4309-4f4a-b8bb-eab5c0ec081e\"}\n[2026-05-28 08:30:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"bc529b16-9502-4df3-b2c0-c63fcf977ed5\",\"trace_id\":\"9dd5d6d0-4cc5-454c-a0c8-0e72b69eeb29\"}\n[2026-05-28 08:30:15] local.INFO: [TextRelayService] Starting sync {\"mailbox\":\"catch-all@txt.staging.jiminny.com\",\"expected_alias\":\"catch-all\",\"expected_host\":\"txt.staging.jiminny.com\"} {\"correlation_id\":\"bc529b16-9502-4df3-b2c0-c63fcf977ed5\",\"trace_id\":\"9dd5d6d0-4cc5-454c-a0c8-0e72b69eeb29\"}\n[2026-05-28 08:30:15] local.INFO: [TextRelayService] Sync completed {\"mailbox\":\"catch-all@txt.staging.jiminny.com\",\"messages_processed\":0,\"message_ids\":[]} {\"correlation_id\":\"bc529b16-9502-4df3-b2c0-c63fcf977ed5\",\"trace_id\":\"9dd5d6d0-4cc5-454c-a0c8-0e72b69eeb29\"}\n[2026-05-28 08:30:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"bc529b16-9502-4df3-b2c0-c63fcf977ed5\",\"trace_id\":\"9dd5d6d0-4cc5-454c-a0c8-0e72b69eeb29\"}\n[2026-05-28 08:30:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"b655bca8-effa-420b-8686-95ba96f27085\",\"trace_id\":\"b1f43a19-c7ad-428e-9933-4e509b5f0055\"}\n[2026-05-28 08:30:18] local.INFO: Running pre-meeting notification command {\"correlation_id\":\"b655bca8-effa-420b-8686-95ba96f27085\",\"trace_id\":\"b1f43a19-c7ad-428e-9933-4e509b5f0055\"}\n[2026-05-28 08:30:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"b655bca8-effa-420b-8686-95ba96f27085\",\"trace_id\":\"b1f43a19-c7ad-428e-9933-4e509b5f0055\"}\n[2026-05-28 08:30:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"5a8493c4-3ef7-4453-98b7-f32225d453fe\",\"trace_id\":\"056f1aea-8825-4e2c-8239-7804086e504e\"}\n[2026-05-28 08:30:20] local.INFO: Running conference:monitor:start command for activities in (2026-05-28 08:20:00, 2026-05-28 08:25:00] {\"correlation_id\":\"5a8493c4-3ef7-4453-98b7-f32225d453fe\",\"trace_id\":\"056f1aea-8825-4e2c-8239-7804086e504e\"}\n[2026-05-28 08:30:20] local.INFO: [conference:monitor:start] No activities found in (2026-05-28 08:20:00, 2026-05-28 08:25:00] {\"correlation_id\":\"5a8493c4-3ef7-4453-98b7-f32225d453fe\",\"trace_id\":\"056f1aea-8825-4e2c-8239-7804086e504e\"}\n[2026-05-28 08:30:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"5a8493c4-3ef7-4453-98b7-f32225d453fe\",\"trace_id\":\"056f1aea-8825-4e2c-8239-7804086e504e\"}\n[2026-05-28 08:30:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"18a2aed9-1aae-4b10-a7fa-f75a147db499\",\"trace_id\":\"fff0c9b2-1c60-4402-b30a-2f41d9b45db3\"}\n[2026-05-28 08:30:22] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesEnded {\"from\":\"08:25\",\"to\":\"08:30\"} {\"correlation_id\":\"18a2aed9-1aae-4b10-a7fa-f75a147db499\",\"trace_id\":\"fff0c9b2-1c60-4402-b30a-2f41d9b45db3\"}\n[2026-05-28 08:30:22] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesWithUnfinishedSession {\"from\":\"22:20\",\"to\":\"22:25\"} {\"correlation_id\":\"18a2aed9-1aae-4b10-a7fa-f75a147db499\",\"trace_id\":\"fff0c9b2-1c60-4402-b30a-2f41d9b45db3\"}\n[2026-05-28 08:30:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"18a2aed9-1aae-4b10-a7fa-f75a147db499\",\"trace_id\":\"fff0c9b2-1c60-4402-b30a-2f41d9b45db3\"}\n[2026-05-28 08:30:23] local.NOTICE: Repairing HubSpot tokens start {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:23] local.INFO: Trying to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:23] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:23] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":59,\"provider\":\"hubspot\",\"refreshToken\":\"97b78f6e2cc49965c00c2492b602b02708b1392551e6b3f113fbaa48992af90b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:26] local.ERROR: Failed to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:26] local.INFO: Trying to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:26] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:26] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":306,\"provider\":\"hubspot\",\"refreshToken\":\"6fa6aa8cc641d131231acc3470f5c03cb3b07b2e580fb18f8acb3b1dbb72549b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.ERROR: Failed to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.INFO: Trying to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1372,\"provider\":\"hubspot\",\"refreshToken\":\"9aa73948c761da29dce46c177cf9aee1fde483a44169ca38723f9f0597d7a8c4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.ERROR: Failed to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.NOTICE: Repairing HubSpot tokens end {\"total\":3,\"fixed\":0,\"failed\":3} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"jiminny:transcription:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"f73071c7-8696-459f-8aff-e61a7c6b30e6\",\"trace_id\":\"d72fc2ce-5064-4877-b401-10891378e1bc\"}\n[2026-05-28 08:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"720d5c87-3d13-4193-87c9-efb8dc6df7c8\",\"trace_id\":\"a9d9c9fe-db29-44a1-a5f6-1905d48dde90\"}\n[2026-05-28 08:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"jiminny:transcription:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"f73071c7-8696-459f-8aff-e61a7c6b30e6\",\"trace_id\":\"d72fc2ce-5064-4877-b401-10891378e1bc\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Command] Starting polling service {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] Service starting {\"memory_limit\":\"256M\",\"max_execution_time\":\"0\",\"initial_memory_mb\":62.0} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] Acquired polling lock {\"expires_at\":\"2026-05-28T08:32:33.444809Z\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"720d5c87-3d13-4193-87c9-efb8dc6df7c8\",\"trace_id\":\"a9d9c9fe-db29-44a1-a5f6-1905d48dde90\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:35] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:reset-governor\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"c692a62b-3b1a-4ff3-b965-388a7d12f619\",\"trace_id\":\"d1bdfdec-73bd-499f-a31e-b25a864da976\"}\n[2026-05-28 08:30:35] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:reset-governor\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"c692a62b-3b1a-4ff3-b965-388a7d12f619\",\"trace_id\":\"d1bdfdec-73bd-499f-a31e-b25a864da976\"}\n[2026-05-28 08:30:38] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:38] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:38] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:39] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814238,\"provider\":\"twilio-flex\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814239,\"provider\":\"xant\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814240,\"provider\":\"apollo\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814241,\"provider\":\"groove\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814242,\"provider\":\"twilio-video\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814243,\"provider\":\"hubspot\",\"team\":\"hubspot\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:fail-stalled\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"f6d797df-5275-4cf1-8ddd-300c125df8da\",\"trace_id\":\"2b46c31f-aced-4324-a70a-6395f0a72618\"}\n[2026-05-28 08:30:42] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:fail-stalled\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"f6d797df-5275-4cf1-8ddd-300c125df8da\",\"trace_id\":\"2b46c31f-aced-4324-a70a-6395f0a72618\"}\n[2026-05-28 08:30:42] local.WARNING: [Salesforce] Account not connected for user {\"userId\":\"cdf8b554-d951-4758-bc2b-c1b85d1cd0b9\",\"account\":null} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"salesforce\",\"crm_owner\":3,\"team_id\":1} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [CrmOwnerResolver] TeamMember found with active crm connection {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1194,\"provider\":\"twilio-flex\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1194,\"provider\":\"twilio-flex\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SyncActivity] Start {\"import_id\":814238,\"provider\":\"twilio-flex\",\"provider_id\":317,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.NOTICE: [TwilioFlex] Calls import start {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.ALERT: [SyncActivity] Failed {\"import_id\":814238,\"provider\":\"twilio-flex\",\"provider_id\":317,\"team\":\"jiminny\",\"team_id\":1,\"reason\":\"[HTTP 401] Unable to fetch page: Authenticate\",\"file\":\"/home/jiminny/vendor/twilio/sdk/src/Twilio/Page.php\",\"line\":60} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SyncActivity] Start {\"import_id\":814239,\"provider\":\"xant\",\"provider_id\":161,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [Salesforce] Performing query {\"query\":\"\n SELECT Playbooks_Call_Date__c,Playbooks_Call_Recording__c,CreatedDate,TaskSubtype,CallType,CallDurationInSeconds,Id,OwnerId,WhoId,WhatId,Priority,ActivityDate,Subject,Description,Status,Type\n FROM Task\n WHERE IsDeleted = false\n AND LastModifiedDate >= :from\n AND LastModifiedDate <= :to\n ORDER BY LastModifiedDate ASC\n LIMIT :limit\",\"params\":{\"from\":\"2026-05-28T08:14:00Z\",\"to\":\"2026-05-28T08:30:00Z\",\"ownerId\":null,\"subType\":null,\"limit\":5000}} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [Salesforce] Sending request {\"endpoint\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=%0A++++++++++++SELECT+Playbooks_Call_Date__c%2CPlaybooks_Call_Recording__c%2CCreatedDate%2CTaskSubtype%2CCallType%2CCallDurationInSeconds%2CId%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%0A++++++++++++++FROM+Task%0A+++++++++++++WHERE+IsDeleted+%3D+false%0A+++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A+++++++++++++++AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z%0A++++++++++ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000 GET\",\"team_id\":1} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:44] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:44] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:44] local.INFO: [Xant (InsideSales)] No calls found. {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] End {\"import_id\":814239,\"provider\":\"xant\",\"provider_id\":161,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Memory usage {\"import_id\":814239,\"provider\":\"xant\",\"provider_id\":161,\"team\":\"jiminny\",\"team_id\":1,\"memory_usage\":24080216,\"memory_real_usage\":65011712,\"pid\":21708} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Start {\"import_id\":814240,\"provider\":\"apollo\",\"provider_id\":441,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Performing query {\"query\":\"\n SELECT AccountId,CreatedDate,TaskSubtype,CallType,Id,OwnerId,WhoId,WhatId,Priority,ActivityDate,Subject,Description,Status,Type\n FROM Task\n WHERE IsDeleted = false\n AND LastModifiedDate >= :from\n AND LastModifiedDate <= :to\n ORDER BY LastModifiedDate ASC\n LIMIT :limit\",\"params\":{\"from\":\"2026-05-28T08:14:00Z\",\"to\":\"2026-05-28T08:30:00Z\",\"ownerId\":null,\"subType\":null,\"limit\":5000}} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Sending request {\"endpoint\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=%0A++++++++++++SELECT+AccountId%2CCreatedDate%2CTaskSubtype%2CCallType%2CId%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%0A++++++++++++++FROM+Task%0A+++++++++++++WHERE+IsDeleted+%3D+false%0A+++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A+++++++++++++++AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z%0A++++++++++ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000 GET\",\"team_id\":1} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Apollo] No calls found. {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] End {\"import_id\":814240,\"provider\":\"apollo\",\"provider_id\":441,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Memory usage {\"import_id\":814240,\"provider\":\"apollo\",\"provider_id\":441,\"team\":\"jiminny\",\"team_id\":1,\"memory_usage\":24242184,\"memory_real_usage\":65011712,\"pid\":21708} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Start {\"import_id\":814241,\"provider\":\"groove\",\"provider_id\":228,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Performing query {\"query\":\"\n SELECT call_recording_url__c,TaskSubtype,CreatedDate,CallType,CallDurationInSeconds,Id,OwnerId,WhoId,WhatId,Priority,ActivityDate,Subject,Description,Status,Type\n FROM Task\n WHERE IsDeleted = false\n AND LastModifiedDate >= :from\n AND LastModifiedDate <= :to\n ORDER BY LastModifiedDate ASC\n LIMIT :limit\",\"params\":{\"from\":\"2026-05-28T08:14:00Z\",\"to\":\"2026-05-28T08:30:00Z\",\"ownerId\":null,\"subType\":null,\"limit\":5000}} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Sending request {\"endpoint\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=%0A++++++++++++SELECT+call_recording_url__c%2CTaskSubtype%2CCreatedDate%2CCallType%2CCallDurationInSeconds%2CId%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%0A++++++++++++++FROM+Task%0A+++++++++++++WHERE+IsDeleted+%3D+false%0A+++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A+++++++++++++++AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z%0A++++++++++ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000 GET\",\"team_id\":1} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"b2b37795-cfa8-472a-b681-322ce27c0e08\",\"trace_id\":\"605e54f2-d4f9-4683-b3fd-6c1c23e691b7\"}\n[2026-05-28 08:30:44] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"b2b37795-cfa8-472a-b681-322ce27c0e08\",\"trace_id\":\"605e54f2-d4f9-4683-b3fd-6c1c23e691b7\"}\n[2026-05-28 08:30:44] local.ERROR: [Salesforce] Request exception [400] \nSELECT call_recording_url__c,TaskSubtype\n ^\nERROR at Row:1:Column:8\nNo such column 'call_recording_url__c' on entity 'Task'. If you are attempting to use a custom field, be sure to append the '__c' after the custom field name. Please reference your WSDL or the describe call for the appropriate names. {\"url\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=%0A++++++++++++SELECT+call_recording_url__c%2CTaskSubtype%2CCreatedDate%2CCallType%2CCallDurationInSeconds%2CId%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%0A++++++++++++++FROM+Task%0A+++++++++++++WHERE+IsDeleted+%3D+false%0A+++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A+++++++++++++++AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z%0A++++++++++ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000\",\"data\":{\"headers\":{\"Authorization\":\"Bearer 00D2g0000008hH4!AQEAQHWUK6nshi8dSCX9CJphxkVivcv_TK98TLOckVy4i0Z1gQfAoRRuH2LVwDXDkbTPs80wvQjczjAlOz0UEtbHoORBLi2u\"}},\"response\":{\"GuzzleHttp\\\\Psr7\\\\Stream\":\"[{\\\"message\\\":\\\"\\\\nSELECT call_recording_url__c,TaskSubtype\\\\n ^\\\\nERROR at Row:1:Column:8\\\\nNo such column 'call_recording_url__c' on entity 'Task'. If you are attempting to use a custom field, be sure to append the '__c' after the custom field name. Please reference your WSDL or the describe call for the appropriate names.\\\",\\\"errorCode\\\":\\\"INVALID_FIELD\\\"}]\"},\"fields\":[]} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.ALERT: [SyncActivity] Failed {\"import_id\":814241,\"provider\":\"groove\",\"provider_id\":228,\"team\":\"jiminny\",\"team_id\":1,\"reason\":\"\nSELECT call_recording_url__c,TaskSubtype\n ^\nERROR at Row:1:Column:8\nNo such column 'call_recording_url__c' on entity 'Task'. If you are attempting to use a custom field, be sure to append the '__c' after the custom field name. Please reference your WSDL or the describe call for the appropriate names.\",\"file\":\"/home/jiminny/app/Services/Crm/Salesforce/Client.php\",\"line\":564} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Start {\"import_id\":814242,\"provider\":\"twilio-video\",\"provider_id\":243,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Performing query {\"query\":\"SELECT Id,OwnerId,WhoId,WhatId,Priority,ActivityDate,Subject,Description,Status,Type,twilio_call_sid__c,Lead_UUID__c,Opportunity__c\n FROM Task\n WHERE Type = 'Video'\n AND isClosed = true\n AND IsDeleted = false\n AND LastModifiedDate >= :from\n AND twilio_call_sid__c != NULL AND LastModifiedDate <= :to ORDER BY LastModifiedDate ASC\n LIMIT :limit\",\"params\":{\"from\":\"2026-05-28T08:14:00Z\",\"to\":\"2026-05-28T08:30:00Z\",\"ownerId\":null,\"subType\":null,\"limit\":5000}} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Sending request {\"endpoint\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=SELECT+Id%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%2Ctwilio_call_sid__c%2CLead_UUID__c%2COpportunity__c%0A++++++++++++++FROM+Task%0A++++++++++++WHERE+Type+%3D+%27Video%27%0A++++++++++++++AND+isClosed+%3D+true%0A++++++++++++++AND+IsDeleted+%3D+false%0A++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A++++++++++++++AND+twilio_call_sid__c+%21%3D+NULL+AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z+ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000 GET\",\"team_id\":1} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [Twilio Video] No calls found. {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] End {\"import_id\":814242,\"provider\":\"twilio-video\",\"provider_id\":243,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] Memory usage {\"import_id\":814242,\"provider\":\"twilio-video\",\"provider_id\":243,\"team\":\"jiminny\",\"team_id\":1,\"memory_usage\":24634032,\"memory_real_usage\":65011712,\"pid\":21708} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":89,\"team_id\":2} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":408,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":408,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] Start {\"import_id\":814243,\"provider\":\"hubspot\",\"provider_id\":31,\"team\":\"hubspot\",\"team_id\":2} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [HubSpot] Search calls for period {\"from\":\"2026-05-28 08:14:00\",\"to\":\"2026-05-28 08:30:00\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] End {\"import_id\":814243,\"provider\":\"hubspot\",\"provider_id\":31,\"team\":\"hubspot\",\"team_id\":2} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] Memory usage {\"import_id\":814243,\"provider\":\"hubspot\",\"provider_id\":31,\"team\":\"hubspot\",\"team_id\":2,\"memory_usage\":24947696,\"memory_real_usage\":65011712,\"pid\":21708} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:46] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"nudges:send\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"f3e257b6-82bb-440c-bf76-855ac528e4e8\",\"trace_id\":\"f8a31218-7290-45ac-8fe1-ffb1b8527521\"}\n[2026-05-28 08:30:46] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"nudges:send\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"f3e257b6-82bb-440c-bf76-855ac528e4e8\",\"trace_id\":\"f8a31218-7290-45ac-8fe1-ffb1b8527521\"}\n[2026-05-28 08:30:50] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"jiminny:playlists:normalize-sort\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"a64b1836-79a1-41da-a4b0-bc0a9703a94b\",\"trace_id\":\"c53faedc-a7a7-41b7-8e51-e84dc2755d79\"}\n[2026-05-28 08:30:50] local.INFO: [Jiminny\\Component\\Playlist\\Command\\NormalizeSortCommand::handle] starting. {\"playlists\":[]} {\"correlation_id\":\"a64b1836-79a1-41da-a4b0-bc0a9703a94b\",\"trace_id\":\"c53faedc-a7a7-41b7-8e51-e84dc2755d79\"}\n[2026-05-28 08:30:50] local.INFO: [Jiminny\\Component\\Playlist\\Command\\NormalizeSortCommand::handle] finished. {\"normalizedPlaylists\":[],\"deletedPlaylists\":[]} {\"correlation_id\":\"a64b1836-79a1-41da-a4b0-bc0a9703a94b\",\"trace_id\":\"c53faedc-a7a7-41b7-8e51-e84dc2755d79\"}\n[2026-05-28 08:30:50] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"jiminny:playlists:normalize-sort\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"a64b1836-79a1-41da-a4b0-bc0a9703a94b\",\"trace_id\":\"c53faedc-a7a7-41b7-8e51-e84dc2755d79\"}\n[2026-05-28 08:30:59] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:59] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:59] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"41db30ba-33c5-46f1-b8bd-5d9e86a70d12\",\"trace_id\":\"a5e2028d-ca41-4ba1-9ddd-a246f83ef4cc\"}\n[2026-05-28 08:31:07] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"41db30ba-33c5-46f1-b8bd-5d9e86a70d12\",\"trace_id\":\"a5e2028d-ca41-4ba1-9ddd-a246f83ef4cc\"}\n[2026-05-28 08:31:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"41db30ba-33c5-46f1-b8bd-5d9e86a70d12\",\"trace_id\":\"a5e2028d-ca41-4ba1-9ddd-a246f83ef4cc\"}\n[2026-05-28 08:31:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"f6ed0a05-caa1-4cb6-ae83-63f44ae4e0d6\",\"trace_id\":\"16cd898d-57a1-4b74-90d1-f9223bbd8d7a\"}\n[2026-05-28 08:31:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"f6ed0a05-caa1-4cb6-ae83-63f44ae4e0d6\",\"trace_id\":\"16cd898d-57a1-4b74-90d1-f9223bbd8d7a\"}\n[2026-05-28 08:31:15] local.NOTICE: Monitoring start {\"correlation_id\":\"cdf384ea-4f59-4411-8ebf-efc299e4a1c8\",\"trace_id\":\"b069d3c8-2f77-4698-bd53-97de373652e8\"}\n[2026-05-28 08:31:15] local.NOTICE: Monitoring end {\"correlation_id\":\"cdf384ea-4f59-4411-8ebf-efc299e4a1c8\",\"trace_id\":\"b069d3c8-2f77-4698-bd53-97de373652e8\"}\n[2026-05-28 08:31:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"940a264b-4aee-40a0-a527-e101ea555a38\",\"trace_id\":\"cd9169ad-4c1e-452d-b7cb-66005aae4dc8\"}\n[2026-05-28 08:31:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"940a264b-4aee-40a0-a527-e101ea555a38\",\"trace_id\":\"cd9169ad-4c1e-452d-b7cb-66005aae4dc8\"}\n[2026-05-28 08:31:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"b798f381-71f2-4c51-a135-f91f09330cfd\",\"trace_id\":\"b44ed325-23f7-4f8b-a447-4c8d0ee99d01\"}\n[2026-05-28 08:31:23] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"b798f381-71f2-4c51-a135-f91f09330cfd\",\"trace_id\":\"b44ed325-23f7-4f8b-a447-4c8d0ee99d01\"}\n[2026-05-28 08:31:24] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"b798f381-71f2-4c51-a135-f91f09330cfd\",\"trace_id\":\"b44ed325-23f7-4f8b-a447-4c8d0ee99d01\"}\n[2026-05-28 08:31:24] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"b798f381-71f2-4c51-a135-f91f09330cfd\",\"trace_id\":\"b44ed325-23f7-4f8b-a447-4c8d0ee99d01\"}\n[2026-05-28 08:31:27] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"2d631328-f2b9-44f3-83d3-613b7b9b9ddc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:27] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"2d631328-f2b9-44f3-83d3-613b7b9b9ddc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"usage\":22563136,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [HubSpot] Syncing opportunities using strategy: lastModified {\"team\":2} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.4,\"average_seconds_per_request\":0.4} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [HubSpot] Synced opportunities {\"team\":2,\"strategies\":\"lastModified\",\"sync_count\":0,\"total\":0,\"last_synced_id\":null,\"duration_ms\":432.6} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"provider\":\"hubspot\",\"status\":\"completed\",\"duration_ms\":543.02,\"usage\":22983640,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"usage\":22961848,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"2ac0447f-3c8c-4ce0-baeb-b63ddb76fa9b\",\"account\":null} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":130,\"team_id\":42} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":23.85,\"usage\":23024000,\"real_usage\":65011712,\"pid\":21703,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"usage\":22984760,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"33e34a7a-1c02-4f04-87ac-22c3a385e6e3\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":306,\"sociable_id\":109,\"provider_user_id\":\"11348452\",\"expires\":1701077403,\"refresh_token_expires\":null,\"provider\":\"hubspot\",\"state\":\"full-refresh\",\"auth_scope\":null,\"retry_after\":null,\"created_at\":\"2020-09-01 16:59:04\",\"updated_at\":\"2023-11-27 09:30:03\"}}} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":109,\"team_id\":29} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":14.98,\"usage\":23047624,\"real_usage\":65011712,\"pid\":21703,\"reason\":\"Your HubSpot account has become disconnected. Please login to Jiminny to reconnect.\"} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal Polling] Service ending {\"runtime_seconds\":56,\"total_cycles\":5,\"files_downloaded\":0,\"empty_files\":0,\"other_portal_skipped\":0,\"total_events\":0,\"events_per_file\":0,\"avg_api_ms\":192.1,\"avg_download_ms\":0.0,\"avg_transform_ms\":0.0,\"avg_process_ms\":0.0,\"peak_memory_mb\":99.88} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal Polling] Released polling lock {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"usage\":23005136,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"71e3aac5-fb66-47c5-a236-2d051ae3e319\",\"account\":null} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":256,\"team_id\":49} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":34.51,\"usage\":23021248,\"real_usage\":65011712,\"pid\":21703,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:32:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"35f98b1b-7b16-4e79-a420-7e9818097d24\",\"trace_id\":\"d66deb58-fa13-486f-a866-2cac402dc589\"}\n[2026-05-28 08:32:06] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"35f98b1b-7b16-4e79-a420-7e9818097d24\",\"trace_id\":\"d66deb58-fa13-486f-a866-2cac402dc589\"}\n[2026-05-28 08:32:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"35f98b1b-7b16-4e79-a420-7e9818097d24\",\"trace_id\":\"d66deb58-fa13-486f-a866-2cac402dc589\"}\n[2026-05-28 08:32:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"bc6784c1-c46f-4295-be09-87334f4baa39\",\"trace_id\":\"74b00236-4ed0-4464-8b07-99c328ab6461\"}\n[2026-05-28 08:32:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"bc6784c1-c46f-4295-be09-87334f4baa39\",\"trace_id\":\"74b00236-4ed0-4464-8b07-99c328ab6461\"}\n[2026-05-28 08:32:11] local.NOTICE: Monitoring start {\"correlation_id\":\"caf4d1dd-2a52-40f5-834a-f9148f642e83\",\"trace_id\":\"1312bdcc-7e8b-480a-a935-2433fb79dc70\"}\n[2026-05-28 08:32:11] local.NOTICE: Monitoring end {\"correlation_id\":\"caf4d1dd-2a52-40f5-834a-f9148f642e83\",\"trace_id\":\"1312bdcc-7e8b-480a-a935-2433fb79dc70\"}\n[2026-05-28 08:32:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"64d86889-1f0d-4f7d-a1ac-6f56e58e775e\",\"trace_id\":\"b184d66b-49f8-40ec-afbe-2e76e9c7d952\"}\n[2026-05-28 08:32:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"64d86889-1f0d-4f7d-a1ac-6f56e58e775e\",\"trace_id\":\"b184d66b-49f8-40ec-afbe-2e76e9c7d952\"}\n[2026-05-28 08:32:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"8e6dd4bc-4f44-4fb2-b2ba-9e2f385996ef\",\"trace_id\":\"7767e0ca-37a3-43a5-972e-ea9a1bedea2f\"}\n[2026-05-28 08:32:20] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"8e6dd4bc-4f44-4fb2-b2ba-9e2f385996ef\",\"trace_id\":\"7767e0ca-37a3-43a5-972e-ea9a1bedea2f\"}\n[2026-05-28 08:32:20] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"8e6dd4bc-4f44-4fb2-b2ba-9e2f385996ef\",\"trace_id\":\"7767e0ca-37a3-43a5-972e-ea9a1bedea2f\"}\n[2026-05-28 08:32:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"8e6dd4bc-4f44-4fb2-b2ba-9e2f385996ef\",\"trace_id\":\"7767e0ca-37a3-43a5-972e-ea9a1bedea2f\"}\n[2026-05-28 08:32:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"6750ab25-6dff-4e7b-9f6e-bc7d1fc4221a\",\"trace_id\":\"3db6ce9b-167d-4214-a32c-67c611aa2bbe\"}\n[2026-05-28 08:32:22] local.INFO: Running conference:monitor:count command for activities in (2026-05-28 08:30:00, 2026-05-28 08:32:00] {\"correlation_id\":\"6750ab25-6dff-4e7b-9f6e-bc7d1fc4221a\",\"trace_id\":\"3db6ce9b-167d-4214-a32c-67c611aa2bbe\"}\n[2026-05-28 08:32:22] local.INFO: [conference:monitor:count] No activities found in (2026-05-28 08:30:00, 2026-05-28 08:32:00] {\"correlation_id\":\"6750ab25-6dff-4e7b-9f6e-bc7d1fc4221a\",\"trace_id\":\"3db6ce9b-167d-4214-a32c-67c611aa2bbe\"}\n[2026-05-28 08:32:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"6750ab25-6dff-4e7b-9f6e-bc7d1fc4221a\",\"trace_id\":\"3db6ce9b-167d-4214-a32c-67c611aa2bbe\"}\n[2026-05-28 08:32:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"04510c2c-638c-4687-81d7-b12e76f41df3\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}\n[2026-05-28 08:32:23] local.INFO: [EmailSchedule] STARTING batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"04510c2c-638c-4687-81d7-b12e76f41df3\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}\n[2026-05-28 08:32:23] local.INFO: [EmailSchedule] FINISHED batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"04510c2c-638c-4687-81d7-b12e76f41df3\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}\n[2026-05-28 08:32:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"04510c2c-638c-4687-81d7-b12e76f41df3\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}\n[2026-05-28 08:32:25] local.INFO: [Jiminny\\Jobs\\Mailbox\\CreateBatches] processed 1 inboxes and created 0 batches {\"userId\":null,\"batchSize\":30,\"maxBatches\":1000} {\"correlation_id\":\"e60597ef-aca8-4bda-bb90-18f01e96874d\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-37482055105397747
|
3613057122943418527
|
visual_change
|
accessibility
|
NULL
|
remote: Resolving deltas: 100% (10/10), completed remote: Resolving deltas: 100% (10/10), completed with 10 local objects.
2 files committed
JY-20915 fix missing header
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
103
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 08:28:04] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"meeting-bot:schedule-bot","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"73199e23-a066-42ba-b189-2802e0869a44","trace_id":"e53672c2-0f50-409d-af25-84ab485c505d"}
[2026-05-28 08:28:04] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {"count":0} {"correlation_id":"73199e23-a066-42ba-b189-2802e0869a44","trace_id":"e53672c2-0f50-409d-af25-84ab485c505d"}
[2026-05-28 08:28:04] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"meeting-bot:schedule-bot","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"73199e23-a066-42ba-b189-2802e0869a44","trace_id":"e53672c2-0f50-409d-af25-84ab485c505d"}
[2026-05-28 08:28:06] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"dialers:monitor-activities","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"741b2c4e-6a44-4c46-b9fb-fce017aef225","trace_id":"804dc547-eb25-4b32-8d0f-c87019773085"}
[2026-05-28 08:28:06] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"dialers:monitor-activities","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"741b2c4e-6a44-4c46-b9fb-fce017aef225","trace_id":"804dc547-eb25-4b32-8d0f-c87019773085"}
[2026-05-28 08:28:09] local.NOTICE: Monitoring start {"correlation_id":"8ae5c131-edd9-463d-8161-875f4d34320f","trace_id":"1b6420c8-ef4e-4566-81b2-688696064648"}
[2026-05-28 08:28:09] local.NOTICE: Monitoring end {"correlation_id":"8ae5c131-edd9-463d-8161-875f4d34320f","trace_id":"1b6420c8-ef4e-4566-81b2-688696064648"}
[2026-05-28 08:28:10] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"mailbox:skip-lists:refresh","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"6f5390d3-abe7-4e56-a662-aeed1098941b","trace_id":"b57dc2df-2f4d-4d3b-b09a-aa6e61205d5e"}
[2026-05-28 08:28:10] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"mailbox:skip-lists:refresh","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"6f5390d3-abe7-4e56-a662-aeed1098941b","trace_id":"b57dc2df-2f4d-4d3b-b09a-aa6e61205d5e"}
[2026-05-28 08:28:12] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"mailbox:batch:process","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"ba694158-ea28-4ac1-b134-83ac485146e0","trace_id":"83a26b74-baa5-407e-9fc2-2b49d65b1c77"}
[2026-05-28 08:28:12] local.INFO: [EmailSchedule] STARTING batch process {"host":"docker_lamp_1"} {"correlation_id":"ba694158-ea28-4ac1-b134-83ac485146e0","trace_id":"83a26b74-baa5-407e-9fc2-2b49d65b1c77"}
[2026-05-28 08:28:12] local.INFO: [EmailSchedule] FINISHED batch process {"host":"docker_lamp_1","processed":0} {"correlation_id":"ba694158-ea28-4ac1-b134-83ac485146e0","trace_id":"83a26b74-baa5-407e-9fc2-2b49d65b1c77"}
[2026-05-28 08:28:12] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"mailbox:batch:process","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"ba694158-ea28-4ac1-b134-83ac485146e0","trace_id":"83a26b74-baa5-407e-9fc2-2b49d65b1c77"}
[2026-05-28 08:28:14] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"conference:monitor:count","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"b79833c7-3eab-4eb7-98bb-42359039b8fb","trace_id":"a8e159bc-867d-40af-bf7d-1228cf6d4f16"}
[2026-05-28 08:28:14] local.INFO: Running conference:monitor:count command for activities in (2026-05-28 08:26:00, 2026-05-28 08:28:00] {"correlation_id":"b79833c7-3eab-4eb7-98bb-42359039b8fb","trace_id":"a8e159bc-867d-40af-bf7d-1228cf6d4f16"}
[2026-05-28 08:28:14] local.INFO: [conference:monitor:count] No activities found in (2026-05-28 08:26:00, 2026-05-28 08:28:00] {"correlation_id":"b79833c7-3eab-4eb7-98bb-42359039b8fb","trace_id":"a8e159bc-867d-40af-bf7d-1228cf6d4f16"}
[2026-05-28 08:28:14] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"conference:monitor:count","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"b79833c7-3eab-4eb7-98bb-42359039b8fb","trace_id":"a8e159bc-867d-40af-bf7d-1228cf6d4f16"}
[2026-05-28 08:28:16] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"mailbox:batch:retry-failed","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"d51071d5-ead0-45f0-a07e-e3234074f884","trace_id":"77173d9f-596f-405f-ae55-ba117b66455d"}
[2026-05-28 08:28:16] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"calendar:sync","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.NOTICE: Calendar sync start {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"mailbox:batch:retry-failed","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"d51071d5-ead0-45f0-a07e-e3234074f884","trace_id":"77173d9f-596f-405f-ae55-ba117b66455d"}
[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1393,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1393,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1393,"provider":"google","refreshToken":"5aa7e2d96b53201cd16fca5d2e4ef3ad03320971fc064781d18aee3ae7b99fbf","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1393,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Account has been deleted"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1393,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1387,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1387,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1387,"provider":"google","refreshToken":"8157ac6de94842937194009e9c50e459253600f799dacf6a40755ffdbeb5bba6","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1387,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Account has been deleted"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1387,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1348,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1348,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1348,"provider":"google","refreshToken":"9e7d13d3032d0cb1b79d8e95aef01383e8e91eb52ff8ee960c8a0b6b95cd8c73","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1348,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1348,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1361,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1361,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1361,"provider":"google","refreshToken":"6c843da199c2b9907445329304fcc4ec5057a4ee748d8299641764395c08e1fd","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1361,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Account has been deleted"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1361,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1310,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1310,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1310,"provider":"google","refreshToken":"e34818922c2830a660813a63f6169a4a9a992ae2cccd7dc8dd7796cfdb470ef1","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1310,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1310,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1333,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1333,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1333,"provider":"google","refreshToken":"6c902986546d8e8da1dc539b046cdc1d458f519acc972e5b5f1d6a1a295165e0","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1333,"provider":"google","responseBody":{"error":"unauthorized_client","error_description":"Unauthorized"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1333,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1368,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1368,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1368,"provider":"google","refreshToken":"d2f128898ff8543bd16b69cfae37896ab85119b0f5ed2b431d739593bb600333","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1368,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1368,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1365,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1365,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1365,"provider":"google","refreshToken":"7676e4a9afcd082b413248ab5ec6e487021fec6a9bdf315860a59cefad9caad8","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1365,"provider":"google","responseBody":{"error":"unauthorized_client","error_description":"Unauthorized"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1365,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1364,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1364,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1364,"provider":"google","refreshToken":"dd5882ebce76e645292ce33ae74238abbb77c0a4ecc6a2bfe723cad82e72ba8e","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1364,"provider":"google","responseBody":{"error":"unauthorized_client","error_description":"Unauthorized"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1364,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1370,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1370,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1370,"provider":"office","refreshToken":"b7ee8035306d0043cea6e00e7c4fe14f745e44074a1194db62a31cdf8b70af3e","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1370,"provider":"office","responseBody":"{\"error\":\"invalid_client\",\"error_description\":\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 41d8db5c-a91f-41a6-9b5c-22a6c99b9100 Correlation ID: 70bc0a6f-1565-4e74-94dc-419d94108fa9 Timestamp: 2026-05-28 08:28:18Z\",\"error_codes\":[7000215],\"timestamp\":\"2026-05-28 08:28:18Z\",\"trace_id\":\"41d8db5c-a91f-41a6-9b5c-22a6c99b9100\",\"correlation_id\":\"70bc0a6f-1565-4e74-94dc-419d94108fa9\",\"error_uri\":\"https://login.microsoftonline.com/error?code=7000215\"}"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1370,"provider":"office","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1202,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1202,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1202,"provider":"office","refreshToken":"b458799ccc29b21a6e2eb5260fdb63e49ccba21bf942a3973fb63799bd7f0afe","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1202,"provider":"office","responseBody":"{\"error\":\"invalid_client\",\"error_description\":\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: d3d14dfc-1b70-40c4-b9db-fab12f748300 Correlation ID: 4c5f746c-8366-44c1-8733-6877607826db Timestamp: 2026-05-28 08:28:19Z\",\"error_codes\":[7000215],\"timestamp\":\"2026-05-28 08:28:19Z\",\"trace_id\":\"d3d14dfc-1b70-40c4-b9db-fab12f748300\",\"correlation_id\":\"4c5f746c-8366-44c1-8733-6877607826db\",\"error_uri\":\"https://login.microsoftonline.com/error?code=7000215\"}"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1202,"provider":"office","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1502,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1502,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: Calendar sync job dispatched {"calendar_id":501} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1300,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1300,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1300,"provider":"google","refreshToken":"4b811db0725fd9602a95943519a7da935e2a5065da7d9ebfcb170752e3e1ddb8","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1300,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Account has been deleted"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1300,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1409,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1409,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1409,"provider":"google","refreshToken":"e2a3f2d06894894eed1ee87d9db1ace77d4d42ee6e1288a8940ad2c10333b0c4","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1409,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1409,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1352,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1352,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1352,"provider":"google","refreshToken":"dd4b16b00fdc1216da6b717c02338c073636e29162826b2de6db3f064fc029eb","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1352,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1352,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1296,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1296,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1296,"provider":"office","refreshToken":"011ae723c9d800c674e0b4be76f49fc046dac7d501b66c59ef0d9549cfa56ae5","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1502,"provider":"google"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1502,"provider":"google"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [Calendar] Processing sync {"calendarId":"a33076c1-8d97-431a-99f0-85c9524e118b","from":null,"to":null,"delta":"CIiFh8TP44kDEIiFh8TP44kDGAUgkZvkzgIokZvkzgI=","last_sync":"2024-12-09 07:12:53","dateMode":"daily"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"integration-app","crm_owner":1695,"team_id":3143} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1502,"provider":"google"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1502,"provider":"google"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1296,"provider":"office","responseBody":"{\"error\":\"invalid_client\",\"error_description\":\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: dd83a147-95bc-407c-8c9b-3c14e7cb7d00 Correlation ID: bb16bae3-b3c4-467e-bd95-4e7ab85364c9 Timestamp: 2026-05-28 08:28:20Z\",\"error_codes\":[7000215],\"timestamp\":\"2026-05-28 08:28:20Z\",\"trace_id\":\"dd83a147-95bc-407c-8c9b-3c14e7cb7d00\",\"correlation_id\":\"bb16bae3-b3c4-467e-bd95-4e7ab85364c9\",\"error_uri\":\"https://login.microsoftonline.com/error?code=7000215\"}"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1296,"provider":"office","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":391,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":391,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":391,"provider":"office","refreshToken":"00045eebae0f39b34887c6d53f92ae78064f7145e1f4b67754aebd03cfb2d881","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [Google Calendar] Failed to watch channel for calendar {"calendarId":"a33076c1-8d97-431a-99f0-85c9524e118b","code":400,"reason":"{
\"error\": {
\"errors\": [
{
\"domain\": \"global\",
\"reason\": \"push.webhookUrlNotHttps\",
\"message\": \"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\"
}
],
\"code\": 400,
\"message\": \"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\"
}
}"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.WARNING: [Calendar] Sync failed {"calendarId":"a33076c1-8d97-431a-99f0-85c9524e118b","code":400,"reason":"{
\"error\": {
\"errors\": [
{
\"domain\": \"global\",
\"reason\": \"push.webhookUrlNotHttps\",
\"message\": \"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\"
}
],
\"code\": 400,
\"message\": \"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\"
}
}"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":391,"provider":"office","responseBody":"{\"error\":\"invalid_client\",\"error_description\":\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 587224ad-f597-4371-b2ba-00fcd2da1b00 Correlation ID: 4e752610-95b1-4606-847f-68e00f90be0a Timestamp: 2026-05-28 08:28:21Z\",\"error_codes\":[7000215],\"timestamp\":\"2026-05-28 08:28:21Z\",\"trace_id\":\"587224ad-f597-4371-b2ba-00fcd2da1b00\",\"correlation_id\":\"4e752610-95b1-4606-847f-68e00f90be0a\",\"error_uri\":\"https://login.microsoftonline.com/error?code=7000215\"}"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":391,"provider":"office","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1271,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1271,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Re...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
81618
|
2833
|
26
|
2026-05-28T08:33:07.556229+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779957187556_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
2 files committed
JY-20915 fix missing header
text 2 files committed
JY-20915 fix missing header
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"2 files committed","depth":2,"bounds":{"left":0.8753325,"top":0.91300875,"width":0.100398935,"height":0.013567438},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"JY-20915 fix missing header","depth":3,"bounds":{"left":0.8753325,"top":0.92897046,"width":0.11037234,"height":0.013567438},"on_screen":true,"value":"JY-20915 fix missing header","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.92897046,"width":0.05817819,"height":0.013567438},"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"bounds":{"left":0.8753325,"top":0.9481245,"width":0.048204787,"height":0.013567438},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09740692,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8374335,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"bounds":{"left":0.85272604,"top":0.019952115,"width":0.062832445,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
3441740384976428124
|
-6865794859280429614
|
click
|
accessibility
|
NULL
|
2 files committed
JY-20915 fix missing header
text 2 files committed
JY-20915 fix missing header
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'...
|
81617
|
NULL
|
NULL
|
NULL
|
|
81619
|
2832
|
23
|
2026-05-28T08:33:07.450520+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779957187450_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
2 files committed
JY-20915 fix missing header
text 2 files committed
JY-20915 fix missing header
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
103
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 08:28:04] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"meeting-bot:schedule-bot","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"73199e23-a066-42ba-b189-2802e0869a44","trace_id":"e53672c2-0f50-409d-af25-84ab485c505d"}
[2026-05-28 08:28:04] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {"count":0} {"correlation_id":"73199e23-a066-42ba-b189-2802e0869a44","trace_id":"e53672c2-0f50-409d-af25-84ab485c505d"}
[2026-05-28 08:28:04] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"meeting-bot:schedule-bot","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"73199e23-a066-42ba-b189-2802e0869a44","trace_id":"e53672c2-0f50-409d-af25-84ab485c505d"}
[2026-05-28 08:28:06] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"dialers:monitor-activities","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"741b2c4e-6a44-4c46-b9fb-fce017aef225","trace_id":"804dc547-eb25-4b32-8d0f-c87019773085"}
[2026-05-28 08:28:06] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"dialers:monitor-activities","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"741b2c4e-6a44-4c46-b9fb-fce017aef225","trace_id":"804dc547-eb25-4b32-8d0f-c87019773085"}
[2026-05-28 08:28:09] local.NOTICE: Monitoring start {"correlation_id":"8ae5c131-edd9-463d-8161-875f4d34320f","trace_id":"1b6420c8-ef4e-4566-81b2-688696064648"}
[2026-05-28 08:28:09] local.NOTICE: Monitoring end {"correlation_id":"8ae5c131-edd9-463d-8161-875f4d34320f","trace_id":"1b6420c8-ef4e-4566-81b2-688696064648"}
[2026-05-28 08:28:10] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"mailbox:skip-lists:refresh","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"6f5390d3-abe7-4e56-a662-aeed1098941b","trace_id":"b57dc2df-2f4d-4d3b-b09a-aa6e61205d5e"}
[2026-05-28 08:28:10] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"mailbox:skip-lists:refresh","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"6f5390d3-abe7-4e56-a662-aeed1098941b","trace_id":"b57dc2df-2f4d-4d3b-b09a-aa6e61205d5e"}
[2026-05-28 08:28:12] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"mailbox:batch:process","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"ba694158-ea28-4ac1-b134-83ac485146e0","trace_id":"83a26b74-baa5-407e-9fc2-2b49d65b1c77"}
[2026-05-28 08:28:12] local.INFO: [EmailSchedule] STARTING batch process {"host":"docker_lamp_1"} {"correlation_id":"ba694158-ea28-4ac1-b134-83ac485146e0","trace_id":"83a26b74-baa5-407e-9fc2-2b49d65b1c77"}
[2026-05-28 08:28:12] local.INFO: [EmailSchedule] FINISHED batch process {"host":"docker_lamp_1","processed":0} {"correlation_id":"ba694158-ea28-4ac1-b134-83ac485146e0","trace_id":"83a26b74-baa5-407e-9fc2-2b49d65b1c77"}
[2026-05-28 08:28:12] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"mailbox:batch:process","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"ba694158-ea28-4ac1-b134-83ac485146e0","trace_id":"83a26b74-baa5-407e-9fc2-2b49d65b1c77"}
[2026-05-28 08:28:14] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"conference:monitor:count","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"b79833c7-3eab-4eb7-98bb-42359039b8fb","trace_id":"a8e159bc-867d-40af-bf7d-1228cf6d4f16"}
[2026-05-28 08:28:14] local.INFO: Running conference:monitor:count command for activities in (2026-05-28 08:26:00, 2026-05-28 08:28:00] {"correlation_id":"b79833c7-3eab-4eb7-98bb-42359039b8fb","trace_id":"a8e159bc-867d-40af-bf7d-1228cf6d4f16"}
[2026-05-28 08:28:14] local.INFO: [conference:monitor:count] No activities found in (2026-05-28 08:26:00, 2026-05-28 08:28:00] {"correlation_id":"b79833c7-3eab-4eb7-98bb-42359039b8fb","trace_id":"a8e159bc-867d-40af-bf7d-1228cf6d4f16"}
[2026-05-28 08:28:14] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"conference:monitor:count","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"b79833c7-3eab-4eb7-98bb-42359039b8fb","trace_id":"a8e159bc-867d-40af-bf7d-1228cf6d4f16"}
[2026-05-28 08:28:16] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"mailbox:batch:retry-failed","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"d51071d5-ead0-45f0-a07e-e3234074f884","trace_id":"77173d9f-596f-405f-ae55-ba117b66455d"}
[2026-05-28 08:28:16] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"calendar:sync","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.NOTICE: Calendar sync start {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"mailbox:batch:retry-failed","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"d51071d5-ead0-45f0-a07e-e3234074f884","trace_id":"77173d9f-596f-405f-ae55-ba117b66455d"}
[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1393,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1393,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1393,"provider":"google","refreshToken":"5aa7e2d96b53201cd16fca5d2e4ef3ad03320971fc064781d18aee3ae7b99fbf","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1393,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Account has been deleted"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1393,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1387,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1387,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1387,"provider":"google","refreshToken":"8157ac6de94842937194009e9c50e459253600f799dacf6a40755ffdbeb5bba6","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1387,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Account has been deleted"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1387,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1348,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1348,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1348,"provider":"google","refreshToken":"9e7d13d3032d0cb1b79d8e95aef01383e8e91eb52ff8ee960c8a0b6b95cd8c73","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1348,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1348,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1361,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1361,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1361,"provider":"google","refreshToken":"6c843da199c2b9907445329304fcc4ec5057a4ee748d8299641764395c08e1fd","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1361,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Account has been deleted"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1361,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1310,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1310,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1310,"provider":"google","refreshToken":"e34818922c2830a660813a63f6169a4a9a992ae2cccd7dc8dd7796cfdb470ef1","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1310,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1310,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1333,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1333,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1333,"provider":"google","refreshToken":"6c902986546d8e8da1dc539b046cdc1d458f519acc972e5b5f1d6a1a295165e0","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1333,"provider":"google","responseBody":{"error":"unauthorized_client","error_description":"Unauthorized"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1333,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1368,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1368,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1368,"provider":"google","refreshToken":"d2f128898ff8543bd16b69cfae37896ab85119b0f5ed2b431d739593bb600333","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1368,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1368,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1365,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1365,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1365,"provider":"google","refreshToken":"7676e4a9afcd082b413248ab5ec6e487021fec6a9bdf315860a59cefad9caad8","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1365,"provider":"google","responseBody":{"error":"unauthorized_client","error_description":"Unauthorized"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1365,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1364,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1364,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1364,"provider":"google","refreshToken":"dd5882ebce76e645292ce33ae74238abbb77c0a4ecc6a2bfe723cad82e72ba8e","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1364,"provider":"google","responseBody":{"error":"unauthorized_client","error_description":"Unauthorized"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1364,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1370,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1370,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1370,"provider":"office","refreshToken":"b7ee8035306d0043cea6e00e7c4fe14f745e44074a1194db62a31cdf8b70af3e","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1370,"provider":"office","responseBody":"{\"error\":\"invalid_client\",\"error_description\":\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 41d8db5c-a91f-41a6-9b5c-22a6c99b9100 Correlation ID: 70bc0a6f-1565-4e74-94dc-419d94108fa9 Timestamp: 2026-05-28 08:28:18Z\",\"error_codes\":[7000215],\"timestamp\":\"2026-05-28 08:28:18Z\",\"trace_id\":\"41d8db5c-a91f-41a6-9b5c-22a6c99b9100\",\"correlation_id\":\"70bc0a6f-1565-4e74-94dc-419d94108fa9\",\"error_uri\":\"https://login.microsoftonline.com/error?code=7000215\"}"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1370,"provider":"office","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1202,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1202,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1202,"provider":"office","refreshToken":"b458799ccc29b21a6e2eb5260fdb63e49ccba21bf942a3973fb63799bd7f0afe","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1202,"provider":"office","responseBody":"{\"error\":\"invalid_client\",\"error_description\":\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: d3d14dfc-1b70-40c4-b9db-fab12f748300 Correlation ID: 4c5f746c-8366-44c1-8733-6877607826db Timestamp: 2026-05-28 08:28:19Z\",\"error_codes\":[7000215],\"timestamp\":\"2026-05-28 08:28:19Z\",\"trace_id\":\"d3d14dfc-1b70-40c4-b9db-fab12f748300\",\"correlation_id\":\"4c5f746c-8366-44c1-8733-6877607826db\",\"error_uri\":\"https://login.microsoftonline.com/error?code=7000215\"}"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1202,"provider":"office","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1502,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1502,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: Calendar sync job dispatched {"calendar_id":501} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1300,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1300,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1300,"provider":"google","refreshToken":"4b811db0725fd9602a95943519a7da935e2a5065da7d9ebfcb170752e3e1ddb8","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1300,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Account has been deleted"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1300,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1409,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1409,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1409,"provider":"google","refreshToken":"e2a3f2d06894894eed1ee87d9db1ace77d4d42ee6e1288a8940ad2c10333b0c4","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1409,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1409,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1352,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1352,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1352,"provider":"google","refreshToken":"dd4b16b00fdc1216da6b717c02338c073636e29162826b2de6db3f064fc029eb","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1352,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1352,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1296,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1296,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1296,"provider":"office","refreshToken":"011ae723c9d800c674e0b4be76f49fc046dac7d501b66c59ef0d9549cfa56ae5","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1502,"provider":"google"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1502,"provider":"google"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [Calendar] Processing sync {"calendarId":"a33076c1-8d97-431a-99f0-85c9524e118b","from":null,"to":null,"delta":"CIiFh8TP44kDEIiFh8TP44kDGAUgkZvkzgIokZvkzgI=","last_sync":"2024-12-09 07:12:53","dateMode":"daily"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"integration-app","crm_owner":1695,"team_id":3143} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1502,"provider":"google"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1502,"provider":"google"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1296,"provider":"office","responseBody":"{\"error\":\"invalid_client\",\"error_description\":\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: dd83a147-95bc-407c-8c9b-3c14e7cb7d00 Correlation ID: bb16bae3-b3c4-467e-bd95-4e7ab85364c9 Timestamp: 2026-05-28 08:28:20Z\",\"error_codes\":[7000215],\"timestamp\":\"2026-05-28 08:28:20Z\",\"trace_id\":\"dd83a147-95bc-407c-8c9b-3c14e7cb7d00\",\"correlation_id\":\"bb16bae3-b3c4-467e-bd95-4e7ab85364c9\",\"error_uri\":\"https://login.microsoftonline.com/error?code=7000215\"}"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1296,"provider":"office","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":391,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":391,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":391,"provider":"office","refreshToken":"00045eebae0f39b34887c6d53f92ae78064f7145e1f4b67754aebd03cfb2d881","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [Google Calendar] Failed to watch channel for calendar {"calendarId":"a33076c1-8d97-431a-99f0-85c9524e118b","code":400,"reason":"{
\"error\": {
\"errors\": [
{
\"domain\": \"global\",
\"reason\": \"push.webhookUrlNotHttps\",
\"message\": \"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\"
}
],
\"code\": 400,
\"message\": \"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\"
}
}"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.WARNING: [Calendar] Sync failed {"calendarId":"a33076c1-8d97-431a-99f0-85c9524e118b","code":400,"reason":"{
\"error\": {
\"errors\": [
{
\"domain\": \"global\",
\"reason\": \"push.webhookUrlNotHttps\",
\"message\": \"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\"
}
],
\"code\": 400,
\"message\": \"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\"
}
}"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":391,"provider":"office","responseBody":"{\"error\":\"invalid_client\",\"error_description\":\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 587224ad-f597-4371-b2ba-00fcd2da1b00 Correlation ID: 4e752610-95b1-4606-847f-68e00f90be0a Timestamp: 2026-05-28 08:28:21Z\",\"error_codes\":[7000215],\"timestamp\":\"2026-05-28 08:28:21Z\",\"trace_id\":\"587224ad-f597-4371-b2ba-00fcd2da1b00\",\"correlation_id\":\"4e752610-95b1-4606-847f-68e00f90be0a\",\"error_uri\":\"https://login.microsoftonline.com/error?code=7000215\"}"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":391,"provider":"office","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1271,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1271,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1271,"provider":"office",...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"2 files committed","depth":2,"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"JY-20915 fix missing header","depth":3,"on_screen":true,"value":"JY-20915 fix missing header","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TextRelayServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TextRelayServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"15","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';\n $expectedHost = config('jiminny.google_text_host');\n\n Log::info('[TextRelayService] Starting sync', [\n 'mailbox' => $mailbox,\n 'expected_alias' => $expectedAlias,\n 'expected_host' => $expectedHost,\n ]);\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded ?? [];\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n\n if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {\n continue;\n }\n\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = new EmailTextRelay($messageId, $relayedText);\n $job->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n Log::info('[TextRelayService] Successfully dispatched message', [\n 'message_id' => $messageId,\n 'text_relay_id' => $relayedText->id,\n 'queue' => Constants::QUEUE_EMAILS,\n ]);\n\n $messageIds[] = $messageId;\n }\n }\n\n Log::info('[TextRelayService] Sync completed', [\n 'mailbox' => $mailbox,\n 'messages_processed' => count($messageIds),\n 'message_ids' => array_slice($messageIds, 0, 10),\n ]);\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, (int) $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to fetch Gmail history', [\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = (int) $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n\n private function isForCurrentEnvironment(\n GoogleGmail $service,\n string $mailbox,\n string $messageId,\n string $expectedAlias,\n string $expectedHost\n ): bool {\n try {\n $message = $service->users_messages->get($mailbox, $messageId);\n $headers = $message->getPayload()->getHeaders();\n\n $originalTo = null;\n $to = null;\n\n foreach ($headers as $header) {\n if ($header->name === 'X-Gm-Original-To') {\n $originalTo = $header->value;\n } elseif ($header->name === 'To') {\n $to = $header->value;\n }\n }\n\n $recipient = $originalTo ?? $to;\n\n if ($recipient !== null) {\n $matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);\n\n if (! $matches) {\n // Sanitize PII by removing plus-tag content for logging\n $sanitizedRecipient = explode('+', $recipient)[0];\n Log::info('[TextRelayService] Refused message', [\n 'message_id' => $messageId,\n 'original_to_sanitized' => $sanitizedRecipient,\n ]);\n }\n\n return $matches;\n }\n\n Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [\n 'message_id' => $messageId,\n ]);\n } catch (\\Exception $e) {\n Log::error('[TextRelayService] Failed to inspect message', [\n 'message_id' => $messageId,\n 'exception' => $e->getMessage(),\n ]);\n \\Sentry::captureException($e);\n }\n\n return false;\n }\n\n private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool\n {\n $parts = explode('@', $recipient, 2);\n\n if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {\n return false;\n }\n\n $localBase = explode('+', $parts[0], 2)[0];\n\n return strcasecmp($localBase, $expectedAlias) === 0;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"103","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-28 08:28:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"73199e23-a066-42ba-b189-2802e0869a44\",\"trace_id\":\"e53672c2-0f50-409d-af25-84ab485c505d\"}\n[2026-05-28 08:28:04] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"73199e23-a066-42ba-b189-2802e0869a44\",\"trace_id\":\"e53672c2-0f50-409d-af25-84ab485c505d\"}\n[2026-05-28 08:28:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"73199e23-a066-42ba-b189-2802e0869a44\",\"trace_id\":\"e53672c2-0f50-409d-af25-84ab485c505d\"}\n[2026-05-28 08:28:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"741b2c4e-6a44-4c46-b9fb-fce017aef225\",\"trace_id\":\"804dc547-eb25-4b32-8d0f-c87019773085\"}\n[2026-05-28 08:28:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"741b2c4e-6a44-4c46-b9fb-fce017aef225\",\"trace_id\":\"804dc547-eb25-4b32-8d0f-c87019773085\"}\n[2026-05-28 08:28:09] local.NOTICE: Monitoring start {\"correlation_id\":\"8ae5c131-edd9-463d-8161-875f4d34320f\",\"trace_id\":\"1b6420c8-ef4e-4566-81b2-688696064648\"}\n[2026-05-28 08:28:09] local.NOTICE: Monitoring end {\"correlation_id\":\"8ae5c131-edd9-463d-8161-875f4d34320f\",\"trace_id\":\"1b6420c8-ef4e-4566-81b2-688696064648\"}\n[2026-05-28 08:28:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"6f5390d3-abe7-4e56-a662-aeed1098941b\",\"trace_id\":\"b57dc2df-2f4d-4d3b-b09a-aa6e61205d5e\"}\n[2026-05-28 08:28:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"6f5390d3-abe7-4e56-a662-aeed1098941b\",\"trace_id\":\"b57dc2df-2f4d-4d3b-b09a-aa6e61205d5e\"}\n[2026-05-28 08:28:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"ba694158-ea28-4ac1-b134-83ac485146e0\",\"trace_id\":\"83a26b74-baa5-407e-9fc2-2b49d65b1c77\"}\n[2026-05-28 08:28:12] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"ba694158-ea28-4ac1-b134-83ac485146e0\",\"trace_id\":\"83a26b74-baa5-407e-9fc2-2b49d65b1c77\"}\n[2026-05-28 08:28:12] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"ba694158-ea28-4ac1-b134-83ac485146e0\",\"trace_id\":\"83a26b74-baa5-407e-9fc2-2b49d65b1c77\"}\n[2026-05-28 08:28:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"ba694158-ea28-4ac1-b134-83ac485146e0\",\"trace_id\":\"83a26b74-baa5-407e-9fc2-2b49d65b1c77\"}\n[2026-05-28 08:28:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"b79833c7-3eab-4eb7-98bb-42359039b8fb\",\"trace_id\":\"a8e159bc-867d-40af-bf7d-1228cf6d4f16\"}\n[2026-05-28 08:28:14] local.INFO: Running conference:monitor:count command for activities in (2026-05-28 08:26:00, 2026-05-28 08:28:00] {\"correlation_id\":\"b79833c7-3eab-4eb7-98bb-42359039b8fb\",\"trace_id\":\"a8e159bc-867d-40af-bf7d-1228cf6d4f16\"}\n[2026-05-28 08:28:14] local.INFO: [conference:monitor:count] No activities found in (2026-05-28 08:26:00, 2026-05-28 08:28:00] {\"correlation_id\":\"b79833c7-3eab-4eb7-98bb-42359039b8fb\",\"trace_id\":\"a8e159bc-867d-40af-bf7d-1228cf6d4f16\"}\n[2026-05-28 08:28:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"b79833c7-3eab-4eb7-98bb-42359039b8fb\",\"trace_id\":\"a8e159bc-867d-40af-bf7d-1228cf6d4f16\"}\n[2026-05-28 08:28:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"d51071d5-ead0-45f0-a07e-e3234074f884\",\"trace_id\":\"77173d9f-596f-405f-ae55-ba117b66455d\"}\n[2026-05-28 08:28:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"calendar:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.NOTICE: Calendar sync start {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"d51071d5-ead0-45f0-a07e-e3234074f884\",\"trace_id\":\"77173d9f-596f-405f-ae55-ba117b66455d\"}\n[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1393,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1393,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1393,\"provider\":\"google\",\"refreshToken\":\"5aa7e2d96b53201cd16fca5d2e4ef3ad03320971fc064781d18aee3ae7b99fbf\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1393,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1393,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1387,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1387,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1387,\"provider\":\"google\",\"refreshToken\":\"8157ac6de94842937194009e9c50e459253600f799dacf6a40755ffdbeb5bba6\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1387,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1387,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1348,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1348,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1348,\"provider\":\"google\",\"refreshToken\":\"9e7d13d3032d0cb1b79d8e95aef01383e8e91eb52ff8ee960c8a0b6b95cd8c73\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1348,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1348,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1361,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1361,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1361,\"provider\":\"google\",\"refreshToken\":\"6c843da199c2b9907445329304fcc4ec5057a4ee748d8299641764395c08e1fd\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1361,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1361,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1310,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1310,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1310,\"provider\":\"google\",\"refreshToken\":\"e34818922c2830a660813a63f6169a4a9a992ae2cccd7dc8dd7796cfdb470ef1\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1310,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1310,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1333,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1333,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1333,\"provider\":\"google\",\"refreshToken\":\"6c902986546d8e8da1dc539b046cdc1d458f519acc972e5b5f1d6a1a295165e0\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1333,\"provider\":\"google\",\"responseBody\":{\"error\":\"unauthorized_client\",\"error_description\":\"Unauthorized\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1333,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1368,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1368,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1368,\"provider\":\"google\",\"refreshToken\":\"d2f128898ff8543bd16b69cfae37896ab85119b0f5ed2b431d739593bb600333\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1368,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1368,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1365,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1365,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1365,\"provider\":\"google\",\"refreshToken\":\"7676e4a9afcd082b413248ab5ec6e487021fec6a9bdf315860a59cefad9caad8\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1365,\"provider\":\"google\",\"responseBody\":{\"error\":\"unauthorized_client\",\"error_description\":\"Unauthorized\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1365,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1364,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1364,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1364,\"provider\":\"google\",\"refreshToken\":\"dd5882ebce76e645292ce33ae74238abbb77c0a4ecc6a2bfe723cad82e72ba8e\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1364,\"provider\":\"google\",\"responseBody\":{\"error\":\"unauthorized_client\",\"error_description\":\"Unauthorized\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1364,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1370,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1370,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1370,\"provider\":\"office\",\"refreshToken\":\"b7ee8035306d0043cea6e00e7c4fe14f745e44074a1194db62a31cdf8b70af3e\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1370,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 41d8db5c-a91f-41a6-9b5c-22a6c99b9100 Correlation ID: 70bc0a6f-1565-4e74-94dc-419d94108fa9 Timestamp: 2026-05-28 08:28:18Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:18Z\\\",\\\"trace_id\\\":\\\"41d8db5c-a91f-41a6-9b5c-22a6c99b9100\\\",\\\"correlation_id\\\":\\\"70bc0a6f-1565-4e74-94dc-419d94108fa9\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1370,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1202,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1202,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1202,\"provider\":\"office\",\"refreshToken\":\"b458799ccc29b21a6e2eb5260fdb63e49ccba21bf942a3973fb63799bd7f0afe\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1202,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: d3d14dfc-1b70-40c4-b9db-fab12f748300 Correlation ID: 4c5f746c-8366-44c1-8733-6877607826db Timestamp: 2026-05-28 08:28:19Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:19Z\\\",\\\"trace_id\\\":\\\"d3d14dfc-1b70-40c4-b9db-fab12f748300\\\",\\\"correlation_id\\\":\\\"4c5f746c-8366-44c1-8733-6877607826db\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1202,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: Calendar sync job dispatched {\"calendar_id\":501} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1300,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1300,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1300,\"provider\":\"google\",\"refreshToken\":\"4b811db0725fd9602a95943519a7da935e2a5065da7d9ebfcb170752e3e1ddb8\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1300,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1300,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1409,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1409,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1409,\"provider\":\"google\",\"refreshToken\":\"e2a3f2d06894894eed1ee87d9db1ace77d4d42ee6e1288a8940ad2c10333b0c4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1409,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1409,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1352,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1352,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1352,\"provider\":\"google\",\"refreshToken\":\"dd4b16b00fdc1216da6b717c02338c073636e29162826b2de6db3f064fc029eb\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1352,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1352,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1296,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1296,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1296,\"provider\":\"office\",\"refreshToken\":\"011ae723c9d800c674e0b4be76f49fc046dac7d501b66c59ef0d9549cfa56ae5\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [Calendar] Processing sync {\"calendarId\":\"a33076c1-8d97-431a-99f0-85c9524e118b\",\"from\":null,\"to\":null,\"delta\":\"CIiFh8TP44kDEIiFh8TP44kDGAUgkZvkzgIokZvkzgI=\",\"last_sync\":\"2024-12-09 07:12:53\",\"dateMode\":\"daily\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"integration-app\",\"crm_owner\":1695,\"team_id\":3143} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1296,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: dd83a147-95bc-407c-8c9b-3c14e7cb7d00 Correlation ID: bb16bae3-b3c4-467e-bd95-4e7ab85364c9 Timestamp: 2026-05-28 08:28:20Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:20Z\\\",\\\"trace_id\\\":\\\"dd83a147-95bc-407c-8c9b-3c14e7cb7d00\\\",\\\"correlation_id\\\":\\\"bb16bae3-b3c4-467e-bd95-4e7ab85364c9\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1296,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":391,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":391,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":391,\"provider\":\"office\",\"refreshToken\":\"00045eebae0f39b34887c6d53f92ae78064f7145e1f4b67754aebd03cfb2d881\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [Google Calendar] Failed to watch channel for calendar {\"calendarId\":\"a33076c1-8d97-431a-99f0-85c9524e118b\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.WARNING: [Calendar] Sync failed {\"calendarId\":\"a33076c1-8d97-431a-99f0-85c9524e118b\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":391,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 587224ad-f597-4371-b2ba-00fcd2da1b00 Correlation ID: 4e752610-95b1-4606-847f-68e00f90be0a Timestamp: 2026-05-28 08:28:21Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:21Z\\\",\\\"trace_id\\\":\\\"587224ad-f597-4371-b2ba-00fcd2da1b00\\\",\\\"correlation_id\\\":\\\"4e752610-95b1-4606-847f-68e00f90be0a\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":391,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1271,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1271,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1271,\"provider\":\"office\",\"refreshToken\":\"118cde2c06993147b07ccaec4cbcd5026a819dea6c71081166a492933e392afb\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1271,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: dd8bf2a7-bc49-43d7-a487-892c51e27600 Correlation ID: 51e3eb6c-c47e-4dd7-91aa-e734fe5b65cf Timestamp: 2026-05-28 08:28:21Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:21Z\\\",\\\"trace_id\\\":\\\"dd8bf2a7-bc49-43d7-a487-892c51e27600\\\",\\\"correlation_id\\\":\\\"51e3eb6c-c47e-4dd7-91aa-e734fe5b65cf\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1271,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1351,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1351,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1351,\"provider\":\"google\",\"refreshToken\":\"4271d15b9e60a606439caddc68337f783e472c85b03dacff14d1b6dfded9051c\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1351,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1351,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1366,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1366,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1366,\"provider\":\"google\",\"refreshToken\":\"ae21385059b2eebfd43f68aecd56eccd702a1aabb6598f1f7ab594ed8af491b4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1366,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1366,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: Calendar sync job dispatched {\"calendar_id\":378} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: Calendar sync job dispatched {\"calendar_id\":504} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.NOTICE: Calendar sync end {\"retrieved_calendars\":31,\"processed_calendars\":3} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"calendar:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [Calendar] Processing sync {\"calendarId\":\"2676cb6d-f86c-427e-bf78-591e388e3c1e\",\"from\":null,\"to\":null,\"delta\":\"CJ_x49O3jpIDEJ_x49O3jpIDGAUgw67KlwMow67KlwM=\",\"last_sync\":\"2026-01-19 07:48:40\",\"dateMode\":\"daily\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.WARNING: [Pipedrive] Account not connected for user {\"userId\":\"e6538737-e7b4-455f-a37a-3e79b665a220\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":1116,\"sociable_id\":241,\"provider_user_id\":\"19555731\",\"expires\":1779091997,\"refresh_token_expires\":null,\"provider\":\"pipedrive\",\"state\":\"full-refresh\",\"auth_scope\":\"base,deals:full,activities:full,contacts:full,search:read\",\"retry_after\":null,\"created_at\":\"2023-09-08 09:44:29\",\"updated_at\":\"2026-05-18 08:13:32\"}}} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"pipedrive\",\"crm_owner\":241,\"team_id\":19} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"pipedrive\",\"team_id\":19} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"pipedrive\",\"team_id\":19} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.WARNING: [Calendar] CRM disconnected for user so events will not be matched {\"provider\":\"pipedrive\",\"user_id\":241,\"message\":\"Your Pipedrive account has become disconnected. Please login to Jiminny to reconnect.\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [Google Calendar] Failed to watch channel for calendar {\"calendarId\":\"2676cb6d-f86c-427e-bf78-591e388e3c1e\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.WARNING: [Calendar] Sync failed {\"calendarId\":\"2676cb6d-f86c-427e-bf78-591e388e3c1e\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [Calendar] Processing sync {\"calendarId\":\"9e8b1a2c-1a8f-42bd-b161-810fc0baf540\",\"from\":null,\"to\":null,\"delta\":\"R0usmcdvmMuZCBYV0hguCBhf4uKqyU9_gdNd-le_nqqau95XAUmZwlIAy2uwtCf5sA67w6NIiDvawUSmVjpTzZO-RsxLdeS-g8Kxy6ODZQxAxafq8AJNx0hJV7T291NUvfaPYqLMv-3je3IdhAPUtXQXkHtYaBAlX_DDBxwc3zYoVVQ8iM9mQkBykdA3sh-KVYPyzi7nK4cZg5Jzpu9tHA.UA7urx3pJyhUhdo_16STIbSNXUrF-qeQVIis9stVUeY\",\"last_sync\":\"2026-05-28 07:44:06\",\"dateMode\":\"daily\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":89,\"team_id\":2} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [MS Office Calendar] Skipping delta sync for daily mode {\"calendarId\":\"9e8b1a2c-1a8f-42bd-b161-810fc0baf540\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:29:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"86a65904-a9f8-43c9-b0c3-1e9c8b4b9541\",\"trace_id\":\"800b02ff-3553-46a3-a8c6-c12324a1ce53\"}\n[2026-05-28 08:29:05] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"86a65904-a9f8-43c9-b0c3-1e9c8b4b9541\",\"trace_id\":\"800b02ff-3553-46a3-a8c6-c12324a1ce53\"}\n[2026-05-28 08:29:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"86a65904-a9f8-43c9-b0c3-1e9c8b4b9541\",\"trace_id\":\"800b02ff-3553-46a3-a8c6-c12324a1ce53\"}\n[2026-05-28 08:29:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"e5162656-5b49-4857-9917-f0cf3ddffe27\",\"trace_id\":\"a3a53cc5-596d-474c-b9c4-f6c5f7ebdfd0\"}\n[2026-05-28 08:29:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"e5162656-5b49-4857-9917-f0cf3ddffe27\",\"trace_id\":\"a3a53cc5-596d-474c-b9c4-f6c5f7ebdfd0\"}\n[2026-05-28 08:29:09] local.NOTICE: Monitoring start {\"correlation_id\":\"f559463e-0c12-46df-8b53-0c50cf4aa3eb\",\"trace_id\":\"5a09aee9-5f75-4bfa-93e4-df0ff76f2326\"}\n[2026-05-28 08:29:09] local.NOTICE: Monitoring end {\"correlation_id\":\"f559463e-0c12-46df-8b53-0c50cf4aa3eb\",\"trace_id\":\"5a09aee9-5f75-4bfa-93e4-df0ff76f2326\"}\n[2026-05-28 08:29:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"9b1cc2f1-0c8a-4aa0-a9e8-57ac879839e4\",\"trace_id\":\"d69dd133-b5f0-4568-81ef-9cce3d1c5c9e\"}\n[2026-05-28 08:29:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"9b1cc2f1-0c8a-4aa0-a9e8-57ac879839e4\",\"trace_id\":\"d69dd133-b5f0-4568-81ef-9cce3d1c5c9e\"}\n[2026-05-28 08:29:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"87e10603-9e6f-4d71-97ab-5ba67103e5fd\",\"trace_id\":\"0aae0afb-779f-4999-892d-0188e14b3dcb\"}\n[2026-05-28 08:29:12] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"87e10603-9e6f-4d71-97ab-5ba67103e5fd\",\"trace_id\":\"0aae0afb-779f-4999-892d-0188e14b3dcb\"}\n[2026-05-28 08:29:12] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"87e10603-9e6f-4d71-97ab-5ba67103e5fd\",\"trace_id\":\"0aae0afb-779f-4999-892d-0188e14b3dcb\"}\n[2026-05-28 08:29:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"87e10603-9e6f-4d71-97ab-5ba67103e5fd\",\"trace_id\":\"0aae0afb-779f-4999-892d-0188e14b3dcb\"}\n[2026-05-28 08:30:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"200b132b-d8db-4010-b968-fe5e3fcc42f1\",\"trace_id\":\"7457715a-3b9d-4c35-a499-455c83e925ab\"}\n[2026-05-28 08:30:04] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"200b132b-d8db-4010-b968-fe5e3fcc42f1\",\"trace_id\":\"7457715a-3b9d-4c35-a499-455c83e925ab\"}\n[2026-05-28 08:30:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"200b132b-d8db-4010-b968-fe5e3fcc42f1\",\"trace_id\":\"7457715a-3b9d-4c35-a499-455c83e925ab\"}\n[2026-05-28 08:30:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"a94ef973-dee7-4bdf-99aa-9ff06f5a5561\",\"trace_id\":\"4e37013f-2993-4c71-87d9-560f8f429d27\"}\n[2026-05-28 08:30:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"a94ef973-dee7-4bdf-99aa-9ff06f5a5561\",\"trace_id\":\"4e37013f-2993-4c71-87d9-560f8f429d27\"}\n[2026-05-28 08:30:07] local.NOTICE: Monitoring start {\"correlation_id\":\"691e7103-784d-4b4a-8036-f3c624a186db\",\"trace_id\":\"991dd947-ed80-4080-8769-8ee7efc4e6a4\"}\n[2026-05-28 08:30:07] local.NOTICE: Monitoring end {\"correlation_id\":\"691e7103-784d-4b4a-8036-f3c624a186db\",\"trace_id\":\"991dd947-ed80-4080-8769-8ee7efc4e6a4\"}\n[2026-05-28 08:30:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"00cf8914-d440-4826-a079-ee4586e76c62\",\"trace_id\":\"d77009ee-8d7b-44ae-bb21-2080b6d48c6c\"}\n[2026-05-28 08:30:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"00cf8914-d440-4826-a079-ee4586e76c62\",\"trace_id\":\"d77009ee-8d7b-44ae-bb21-2080b6d48c6c\"}\n[2026-05-28 08:30:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"7c9550d0-42ed-4b1d-b5b3-7dca67f743ec\",\"trace_id\":\"84177853-9530-4b1e-bde6-3dc0c71883ee\"}\n[2026-05-28 08:30:10] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"7c9550d0-42ed-4b1d-b5b3-7dca67f743ec\",\"trace_id\":\"84177853-9530-4b1e-bde6-3dc0c71883ee\"}\n[2026-05-28 08:30:10] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"7c9550d0-42ed-4b1d-b5b3-7dca67f743ec\",\"trace_id\":\"84177853-9530-4b1e-bde6-3dc0c71883ee\"}\n[2026-05-28 08:30:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"7c9550d0-42ed-4b1d-b5b3-7dca67f743ec\",\"trace_id\":\"84177853-9530-4b1e-bde6-3dc0c71883ee\"}\n[2026-05-28 08:30:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"85cc6c92-262b-45c5-bbcc-4a084137fde3\",\"trace_id\":\"058bc9a3-67af-49b6-a87c-8a0a0bc0c47a\"}\n[2026-05-28 08:30:12] local.INFO: Running conference:monitor:count command for activities in (2026-05-28 08:28:00, 2026-05-28 08:30:00] {\"correlation_id\":\"85cc6c92-262b-45c5-bbcc-4a084137fde3\",\"trace_id\":\"058bc9a3-67af-49b6-a87c-8a0a0bc0c47a\"}\n[2026-05-28 08:30:12] local.INFO: [conference:monitor:count] No activities found in (2026-05-28 08:28:00, 2026-05-28 08:30:00] {\"correlation_id\":\"85cc6c92-262b-45c5-bbcc-4a084137fde3\",\"trace_id\":\"058bc9a3-67af-49b6-a87c-8a0a0bc0c47a\"}\n[2026-05-28 08:30:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"85cc6c92-262b-45c5-bbcc-4a084137fde3\",\"trace_id\":\"058bc9a3-67af-49b6-a87c-8a0a0bc0c47a\"}\n[2026-05-28 08:30:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"5083d024-d669-4c6a-bde3-ce084d6a628c\",\"trace_id\":\"83110e1f-4309-4f4a-b8bb-eab5c0ec081e\"}\n[2026-05-28 08:30:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"5083d024-d669-4c6a-bde3-ce084d6a628c\",\"trace_id\":\"83110e1f-4309-4f4a-b8bb-eab5c0ec081e\"}\n[2026-05-28 08:30:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"bc529b16-9502-4df3-b2c0-c63fcf977ed5\",\"trace_id\":\"9dd5d6d0-4cc5-454c-a0c8-0e72b69eeb29\"}\n[2026-05-28 08:30:15] local.INFO: [TextRelayService] Starting sync {\"mailbox\":\"catch-all@txt.staging.jiminny.com\",\"expected_alias\":\"catch-all\",\"expected_host\":\"txt.staging.jiminny.com\"} {\"correlation_id\":\"bc529b16-9502-4df3-b2c0-c63fcf977ed5\",\"trace_id\":\"9dd5d6d0-4cc5-454c-a0c8-0e72b69eeb29\"}\n[2026-05-28 08:30:15] local.INFO: [TextRelayService] Sync completed {\"mailbox\":\"catch-all@txt.staging.jiminny.com\",\"messages_processed\":0,\"message_ids\":[]} {\"correlation_id\":\"bc529b16-9502-4df3-b2c0-c63fcf977ed5\",\"trace_id\":\"9dd5d6d0-4cc5-454c-a0c8-0e72b69eeb29\"}\n[2026-05-28 08:30:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"bc529b16-9502-4df3-b2c0-c63fcf977ed5\",\"trace_id\":\"9dd5d6d0-4cc5-454c-a0c8-0e72b69eeb29\"}\n[2026-05-28 08:30:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"b655bca8-effa-420b-8686-95ba96f27085\",\"trace_id\":\"b1f43a19-c7ad-428e-9933-4e509b5f0055\"}\n[2026-05-28 08:30:18] local.INFO: Running pre-meeting notification command {\"correlation_id\":\"b655bca8-effa-420b-8686-95ba96f27085\",\"trace_id\":\"b1f43a19-c7ad-428e-9933-4e509b5f0055\"}\n[2026-05-28 08:30:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"b655bca8-effa-420b-8686-95ba96f27085\",\"trace_id\":\"b1f43a19-c7ad-428e-9933-4e509b5f0055\"}\n[2026-05-28 08:30:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"5a8493c4-3ef7-4453-98b7-f32225d453fe\",\"trace_id\":\"056f1aea-8825-4e2c-8239-7804086e504e\"}\n[2026-05-28 08:30:20] local.INFO: Running conference:monitor:start command for activities in (2026-05-28 08:20:00, 2026-05-28 08:25:00] {\"correlation_id\":\"5a8493c4-3ef7-4453-98b7-f32225d453fe\",\"trace_id\":\"056f1aea-8825-4e2c-8239-7804086e504e\"}\n[2026-05-28 08:30:20] local.INFO: [conference:monitor:start] No activities found in (2026-05-28 08:20:00, 2026-05-28 08:25:00] {\"correlation_id\":\"5a8493c4-3ef7-4453-98b7-f32225d453fe\",\"trace_id\":\"056f1aea-8825-4e2c-8239-7804086e504e\"}\n[2026-05-28 08:30:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"5a8493c4-3ef7-4453-98b7-f32225d453fe\",\"trace_id\":\"056f1aea-8825-4e2c-8239-7804086e504e\"}\n[2026-05-28 08:30:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"18a2aed9-1aae-4b10-a7fa-f75a147db499\",\"trace_id\":\"fff0c9b2-1c60-4402-b30a-2f41d9b45db3\"}\n[2026-05-28 08:30:22] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesEnded {\"from\":\"08:25\",\"to\":\"08:30\"} {\"correlation_id\":\"18a2aed9-1aae-4b10-a7fa-f75a147db499\",\"trace_id\":\"fff0c9b2-1c60-4402-b30a-2f41d9b45db3\"}\n[2026-05-28 08:30:22] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesWithUnfinishedSession {\"from\":\"22:20\",\"to\":\"22:25\"} {\"correlation_id\":\"18a2aed9-1aae-4b10-a7fa-f75a147db499\",\"trace_id\":\"fff0c9b2-1c60-4402-b30a-2f41d9b45db3\"}\n[2026-05-28 08:30:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"18a2aed9-1aae-4b10-a7fa-f75a147db499\",\"trace_id\":\"fff0c9b2-1c60-4402-b30a-2f41d9b45db3\"}\n[2026-05-28 08:30:23] local.NOTICE: Repairing HubSpot tokens start {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:23] local.INFO: Trying to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:23] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:23] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":59,\"provider\":\"hubspot\",\"refreshToken\":\"97b78f6e2cc49965c00c2492b602b02708b1392551e6b3f113fbaa48992af90b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:26] local.ERROR: Failed to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:26] local.INFO: Trying to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:26] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:26] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":306,\"provider\":\"hubspot\",\"refreshToken\":\"6fa6aa8cc641d131231acc3470f5c03cb3b07b2e580fb18f8acb3b1dbb72549b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.ERROR: Failed to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.INFO: Trying to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1372,\"provider\":\"hubspot\",\"refreshToken\":\"9aa73948c761da29dce46c177cf9aee1fde483a44169ca38723f9f0597d7a8c4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.ERROR: Failed to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.NOTICE: Repairing HubSpot tokens end {\"total\":3,\"fixed\":0,\"failed\":3} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"jiminny:transcription:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"f73071c7-8696-459f-8aff-e61a7c6b30e6\",\"trace_id\":\"d72fc2ce-5064-4877-b401-10891378e1bc\"}\n[2026-05-28 08:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"720d5c87-3d13-4193-87c9-efb8dc6df7c8\",\"trace_id\":\"a9d9c9fe-db29-44a1-a5f6-1905d48dde90\"}\n[2026-05-28 08:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"jiminny:transcription:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"f73071c7-8696-459f-8aff-e61a7c6b30e6\",\"trace_id\":\"d72fc2ce-5064-4877-b401-10891378e1bc\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Command] Starting polling service {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] Service starting {\"memory_limit\":\"256M\",\"max_execution_time\":\"0\",\"initial_memory_mb\":62.0} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] Acquired polling lock {\"expires_at\":\"2026-05-28T08:32:33.444809Z\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"720d5c87-3d13-4193-87c9-efb8dc6df7c8\",\"trace_id\":\"a9d9c9fe-db29-44a1-a5f6-1905d48dde90\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:35] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:reset-governor\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"c692a62b-3b1a-4ff3-b965-388a7d12f619\",\"trace_id\":\"d1bdfdec-73bd-499f-a31e-b25a864da976\"}\n[2026-05-28 08:30:35] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:reset-governor\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"c692a62b-3b1a-4ff3-b965-388a7d12f619\",\"trace_id\":\"d1bdfdec-73bd-499f-a31e-b25a864da976\"}\n[2026-05-28 08:30:38] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:38] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:38] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:39] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814238,\"provider\":\"twilio-flex\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814239,\"provider\":\"xant\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814240,\"provider\":\"apollo\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814241,\"provider\":\"groove\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814242,\"provider\":\"twilio-video\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814243,\"provider\":\"hubspot\",\"team\":\"hubspot\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:fail-stalled\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"f6d797df-5275-4cf1-8ddd-300c125df8da\",\"trace_id\":\"2b46c31f-aced-4324-a70a-6395f0a72618\"}\n[2026-05-28 08:30:42] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:fail-stalled\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"f6d797df-5275-4cf1-8ddd-300c125df8da\",\"trace_id\":\"2b46c31f-aced-4324-a70a-6395f0a72618\"}\n[2026-05-28 08:30:42] local.WARNING: [Salesforce] Account not connected for user {\"userId\":\"cdf8b554-d951-4758-bc2b-c1b85d1cd0b9\",\"account\":null} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"salesforce\",\"crm_owner\":3,\"team_id\":1} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [CrmOwnerResolver] TeamMember found with active crm connection {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1194,\"provider\":\"twilio-flex\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1194,\"provider\":\"twilio-flex\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SyncActivity] Start {\"import_id\":814238,\"provider\":\"twilio-flex\",\"provider_id\":317,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.NOTICE: [TwilioFlex] Calls import start {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.ALERT: [SyncActivity] Failed {\"import_id\":814238,\"provider\":\"twilio-flex\",\"provider_id\":317,\"team\":\"jiminny\",\"team_id\":1,\"reason\":\"[HTTP 401] Unable to fetch page: Authenticate\",\"file\":\"/home/jiminny/vendor/twilio/sdk/src/Twilio/Page.php\",\"line\":60} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SyncActivity] Start {\"import_id\":814239,\"provider\":\"xant\",\"provider_id\":161,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [Salesforce] Performing query {\"query\":\"\n SELECT Playbooks_Call_Date__c,Playbooks_Call_Recording__c,CreatedDate,TaskSubtype,CallType,CallDurationInSeconds,Id,OwnerId,WhoId,WhatId,Priority,ActivityDate,Subject,Description,Status,Type\n FROM Task\n WHERE IsDeleted = false\n AND LastModifiedDate >= :from\n AND LastModifiedDate <= :to\n ORDER BY LastModifiedDate ASC\n LIMIT :limit\",\"params\":{\"from\":\"2026-05-28T08:14:00Z\",\"to\":\"2026-05-28T08:30:00Z\",\"ownerId\":null,\"subType\":null,\"limit\":5000}} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [Salesforce] Sending request {\"endpoint\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=%0A++++++++++++SELECT+Playbooks_Call_Date__c%2CPlaybooks_Call_Recording__c%2CCreatedDate%2CTaskSubtype%2CCallType%2CCallDurationInSeconds%2CId%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%0A++++++++++++++FROM+Task%0A+++++++++++++WHERE+IsDeleted+%3D+false%0A+++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A+++++++++++++++AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z%0A++++++++++ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000 GET\",\"team_id\":1} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:44] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:44] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:44] local.INFO: [Xant (InsideSales)] No calls found. {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] End {\"import_id\":814239,\"provider\":\"xant\",\"provider_id\":161,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Memory usage {\"import_id\":814239,\"provider\":\"xant\",\"provider_id\":161,\"team\":\"jiminny\",\"team_id\":1,\"memory_usage\":24080216,\"memory_real_usage\":65011712,\"pid\":21708} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Start {\"import_id\":814240,\"provider\":\"apollo\",\"provider_id\":441,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Performing query {\"query\":\"\n SELECT AccountId,CreatedDate,TaskSubtype,CallType,Id,OwnerId,WhoId,WhatId,Priority,ActivityDate,Subject,Description,Status,Type\n FROM Task\n WHERE IsDeleted = false\n AND LastModifiedDate >= :from\n AND LastModifiedDate <= :to\n ORDER BY LastModifiedDate ASC\n LIMIT :limit\",\"params\":{\"from\":\"2026-05-28T08:14:00Z\",\"to\":\"2026-05-28T08:30:00Z\",\"ownerId\":null,\"subType\":null,\"limit\":5000}} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Sending request {\"endpoint\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=%0A++++++++++++SELECT+AccountId%2CCreatedDate%2CTaskSubtype%2CCallType%2CId%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%0A++++++++++++++FROM+Task%0A+++++++++++++WHERE+IsDeleted+%3D+false%0A+++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A+++++++++++++++AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z%0A++++++++++ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000 GET\",\"team_id\":1} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Apollo] No calls found. {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] End {\"import_id\":814240,\"provider\":\"apollo\",\"provider_id\":441,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Memory usage {\"import_id\":814240,\"provider\":\"apollo\",\"provider_id\":441,\"team\":\"jiminny\",\"team_id\":1,\"memory_usage\":24242184,\"memory_real_usage\":65011712,\"pid\":21708} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Start {\"import_id\":814241,\"provider\":\"groove\",\"provider_id\":228,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Performing query {\"query\":\"\n SELECT call_recording_url__c,TaskSubtype,CreatedDate,CallType,CallDurationInSeconds,Id,OwnerId,WhoId,WhatId,Priority,ActivityDate,Subject,Description,Status,Type\n FROM Task\n WHERE IsDeleted = false\n AND LastModifiedDate >= :from\n AND LastModifiedDate <= :to\n ORDER BY LastModifiedDate ASC\n LIMIT :limit\",\"params\":{\"from\":\"2026-05-28T08:14:00Z\",\"to\":\"2026-05-28T08:30:00Z\",\"ownerId\":null,\"subType\":null,\"limit\":5000}} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Sending request {\"endpoint\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=%0A++++++++++++SELECT+call_recording_url__c%2CTaskSubtype%2CCreatedDate%2CCallType%2CCallDurationInSeconds%2CId%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%0A++++++++++++++FROM+Task%0A+++++++++++++WHERE+IsDeleted+%3D+false%0A+++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A+++++++++++++++AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z%0A++++++++++ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000 GET\",\"team_id\":1} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"b2b37795-cfa8-472a-b681-322ce27c0e08\",\"trace_id\":\"605e54f2-d4f9-4683-b3fd-6c1c23e691b7\"}\n[2026-05-28 08:30:44] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"b2b37795-cfa8-472a-b681-322ce27c0e08\",\"trace_id\":\"605e54f2-d4f9-4683-b3fd-6c1c23e691b7\"}\n[2026-05-28 08:30:44] local.ERROR: [Salesforce] Request exception [400] \nSELECT call_recording_url__c,TaskSubtype\n ^\nERROR at Row:1:Column:8\nNo such column 'call_recording_url__c' on entity 'Task'. If you are attempting to use a custom field, be sure to append the '__c' after the custom field name. Please reference your WSDL or the describe call for the appropriate names. {\"url\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=%0A++++++++++++SELECT+call_recording_url__c%2CTaskSubtype%2CCreatedDate%2CCallType%2CCallDurationInSeconds%2CId%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%0A++++++++++++++FROM+Task%0A+++++++++++++WHERE+IsDeleted+%3D+false%0A+++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A+++++++++++++++AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z%0A++++++++++ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000\",\"data\":{\"headers\":{\"Authorization\":\"Bearer 00D2g0000008hH4!AQEAQHWUK6nshi8dSCX9CJphxkVivcv_TK98TLOckVy4i0Z1gQfAoRRuH2LVwDXDkbTPs80wvQjczjAlOz0UEtbHoORBLi2u\"}},\"response\":{\"GuzzleHttp\\\\Psr7\\\\Stream\":\"[{\\\"message\\\":\\\"\\\\nSELECT call_recording_url__c,TaskSubtype\\\\n ^\\\\nERROR at Row:1:Column:8\\\\nNo such column 'call_recording_url__c' on entity 'Task'. If you are attempting to use a custom field, be sure to append the '__c' after the custom field name. Please reference your WSDL or the describe call for the appropriate names.\\\",\\\"errorCode\\\":\\\"INVALID_FIELD\\\"}]\"},\"fields\":[]} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.ALERT: [SyncActivity] Failed {\"import_id\":814241,\"provider\":\"groove\",\"provider_id\":228,\"team\":\"jiminny\",\"team_id\":1,\"reason\":\"\nSELECT call_recording_url__c,TaskSubtype\n ^\nERROR at Row:1:Column:8\nNo such column 'call_recording_url__c' on entity 'Task'. If you are attempting to use a custom field, be sure to append the '__c' after the custom field name. Please reference your WSDL or the describe call for the appropriate names.\",\"file\":\"/home/jiminny/app/Services/Crm/Salesforce/Client.php\",\"line\":564} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Start {\"import_id\":814242,\"provider\":\"twilio-video\",\"provider_id\":243,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Performing query {\"query\":\"SELECT Id,OwnerId,WhoId,WhatId,Priority,ActivityDate,Subject,Description,Status,Type,twilio_call_sid__c,Lead_UUID__c,Opportunity__c\n FROM Task\n WHERE Type = 'Video'\n AND isClosed = true\n AND IsDeleted = false\n AND LastModifiedDate >= :from\n AND twilio_call_sid__c != NULL AND LastModifiedDate <= :to ORDER BY LastModifiedDate ASC\n LIMIT :limit\",\"params\":{\"from\":\"2026-05-28T08:14:00Z\",\"to\":\"2026-05-28T08:30:00Z\",\"ownerId\":null,\"subType\":null,\"limit\":5000}} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Sending request {\"endpoint\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=SELECT+Id%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%2Ctwilio_call_sid__c%2CLead_UUID__c%2COpportunity__c%0A++++++++++++++FROM+Task%0A++++++++++++WHERE+Type+%3D+%27Video%27%0A++++++++++++++AND+isClosed+%3D+true%0A++++++++++++++AND+IsDeleted+%3D+false%0A++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A++++++++++++++AND+twilio_call_sid__c+%21%3D+NULL+AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z+ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000 GET\",\"team_id\":1} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [Twilio Video] No calls found. {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] End {\"import_id\":814242,\"provider\":\"twilio-video\",\"provider_id\":243,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] Memory usage {\"import_id\":814242,\"provider\":\"twilio-video\",\"provider_id\":243,\"team\":\"jiminny\",\"team_id\":1,\"memory_usage\":24634032,\"memory_real_usage\":65011712,\"pid\":21708} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":89,\"team_id\":2} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":408,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":408,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] Start {\"import_id\":814243,\"provider\":\"hubspot\",\"provider_id\":31,\"team\":\"hubspot\",\"team_id\":2} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [HubSpot] Search calls for period {\"from\":\"2026-05-28 08:14:00\",\"to\":\"2026-05-28 08:30:00\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] End {\"import_id\":814243,\"provider\":\"hubspot\",\"provider_id\":31,\"team\":\"hubspot\",\"team_id\":2} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] Memory usage {\"import_id\":814243,\"provider\":\"hubspot\",\"provider_id\":31,\"team\":\"hubspot\",\"team_id\":2,\"memory_usage\":24947696,\"memory_real_usage\":65011712,\"pid\":21708} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:46] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"nudges:send\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"f3e257b6-82bb-440c-bf76-855ac528e4e8\",\"trace_id\":\"f8a31218-7290-45ac-8fe1-ffb1b8527521\"}\n[2026-05-28 08:30:46] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"nudges:send\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"f3e257b6-82bb-440c-bf76-855ac528e4e8\",\"trace_id\":\"f8a31218-7290-45ac-8fe1-ffb1b8527521\"}\n[2026-05-28 08:30:50] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"jiminny:playlists:normalize-sort\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"a64b1836-79a1-41da-a4b0-bc0a9703a94b\",\"trace_id\":\"c53faedc-a7a7-41b7-8e51-e84dc2755d79\"}\n[2026-05-28 08:30:50] local.INFO: [Jiminny\\Component\\Playlist\\Command\\NormalizeSortCommand::handle] starting. {\"playlists\":[]} {\"correlation_id\":\"a64b1836-79a1-41da-a4b0-bc0a9703a94b\",\"trace_id\":\"c53faedc-a7a7-41b7-8e51-e84dc2755d79\"}\n[2026-05-28 08:30:50] local.INFO: [Jiminny\\Component\\Playlist\\Command\\NormalizeSortCommand::handle] finished. {\"normalizedPlaylists\":[],\"deletedPlaylists\":[]} {\"correlation_id\":\"a64b1836-79a1-41da-a4b0-bc0a9703a94b\",\"trace_id\":\"c53faedc-a7a7-41b7-8e51-e84dc2755d79\"}\n[2026-05-28 08:30:50] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"jiminny:playlists:normalize-sort\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"a64b1836-79a1-41da-a4b0-bc0a9703a94b\",\"trace_id\":\"c53faedc-a7a7-41b7-8e51-e84dc2755d79\"}\n[2026-05-28 08:30:59] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:59] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:59] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"41db30ba-33c5-46f1-b8bd-5d9e86a70d12\",\"trace_id\":\"a5e2028d-ca41-4ba1-9ddd-a246f83ef4cc\"}\n[2026-05-28 08:31:07] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"41db30ba-33c5-46f1-b8bd-5d9e86a70d12\",\"trace_id\":\"a5e2028d-ca41-4ba1-9ddd-a246f83ef4cc\"}\n[2026-05-28 08:31:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"41db30ba-33c5-46f1-b8bd-5d9e86a70d12\",\"trace_id\":\"a5e2028d-ca41-4ba1-9ddd-a246f83ef4cc\"}\n[2026-05-28 08:31:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"f6ed0a05-caa1-4cb6-ae83-63f44ae4e0d6\",\"trace_id\":\"16cd898d-57a1-4b74-90d1-f9223bbd8d7a\"}\n[2026-05-28 08:31:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"f6ed0a05-caa1-4cb6-ae83-63f44ae4e0d6\",\"trace_id\":\"16cd898d-57a1-4b74-90d1-f9223bbd8d7a\"}\n[2026-05-28 08:31:15] local.NOTICE: Monitoring start {\"correlation_id\":\"cdf384ea-4f59-4411-8ebf-efc299e4a1c8\",\"trace_id\":\"b069d3c8-2f77-4698-bd53-97de373652e8\"}\n[2026-05-28 08:31:15] local.NOTICE: Monitoring end {\"correlation_id\":\"cdf384ea-4f59-4411-8ebf-efc299e4a1c8\",\"trace_id\":\"b069d3c8-2f77-4698-bd53-97de373652e8\"}\n[2026-05-28 08:31:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"940a264b-4aee-40a0-a527-e101ea555a38\",\"trace_id\":\"cd9169ad-4c1e-452d-b7cb-66005aae4dc8\"}\n[2026-05-28 08:31:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"940a264b-4aee-40a0-a527-e101ea555a38\",\"trace_id\":\"cd9169ad-4c1e-452d-b7cb-66005aae4dc8\"}\n[2026-05-28 08:31:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"b798f381-71f2-4c51-a135-f91f09330cfd\",\"trace_id\":\"b44ed325-23f7-4f8b-a447-4c8d0ee99d01\"}\n[2026-05-28 08:31:23] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"b798f381-71f2-4c51-a135-f91f09330cfd\",\"trace_id\":\"b44ed325-23f7-4f8b-a447-4c8d0ee99d01\"}\n[2026-05-28 08:31:24] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"b798f381-71f2-4c51-a135-f91f09330cfd\",\"trace_id\":\"b44ed325-23f7-4f8b-a447-4c8d0ee99d01\"}\n[2026-05-28 08:31:24] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"b798f381-71f2-4c51-a135-f91f09330cfd\",\"trace_id\":\"b44ed325-23f7-4f8b-a447-4c8d0ee99d01\"}\n[2026-05-28 08:31:27] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"2d631328-f2b9-44f3-83d3-613b7b9b9ddc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:27] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"2d631328-f2b9-44f3-83d3-613b7b9b9ddc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"usage\":22563136,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [HubSpot] Syncing opportunities using strategy: lastModified {\"team\":2} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.4,\"average_seconds_per_request\":0.4} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [HubSpot] Synced opportunities {\"team\":2,\"strategies\":\"lastModified\",\"sync_count\":0,\"total\":0,\"last_synced_id\":null,\"duration_ms\":432.6} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"provider\":\"hubspot\",\"status\":\"completed\",\"duration_ms\":543.02,\"usage\":22983640,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"usage\":22961848,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"2ac0447f-3c8c-4ce0-baeb-b63ddb76fa9b\",\"account\":null} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":130,\"team_id\":42} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":23.85,\"usage\":23024000,\"real_usage\":65011712,\"pid\":21703,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"usage\":22984760,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"33e34a7a-1c02-4f04-87ac-22c3a385e6e3\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":306,\"sociable_id\":109,\"provider_user_id\":\"11348452\",\"expires\":1701077403,\"refresh_token_expires\":null,\"provider\":\"hubspot\",\"state\":\"full-refresh\",\"auth_scope\":null,\"retry_after\":null,\"created_at\":\"2020-09-01 16:59:04\",\"updated_at\":\"2023-11-27 09:30:03\"}}} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":109,\"team_id\":29} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":14.98,\"usage\":23047624,\"real_usage\":65011712,\"pid\":21703,\"reason\":\"Your HubSpot account has become disconnected. Please login to Jiminny to reconnect.\"} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal Polling] Service ending {\"runtime_seconds\":56,\"total_cycles\":5,\"files_downloaded\":0,\"empty_files\":0,\"other_portal_skipped\":0,\"total_events\":0,\"events_per_file\":0,\"avg_api_ms\":192.1,\"avg_download_ms\":0.0,\"avg_transform_ms\":0.0,\"avg_process_ms\":0.0,\"peak_memory_mb\":99.88} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal Polling] Released polling lock {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"usage\":23005136,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"71e3aac5-fb66-47c5-a236-2d051ae3e319\",\"account\":null} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":256,\"team_id\":49} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":34.51,\"usage\":23021248,\"real_usage\":65011712,\"pid\":21703,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:32:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"35f98b1b-7b16-4e79-a420-7e9818097d24\",\"trace_id\":\"d66deb58-fa13-486f-a866-2cac402dc589\"}\n[2026-05-28 08:32:06] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"35f98b1b-7b16-4e79-a420-7e9818097d24\",\"trace_id\":\"d66deb58-fa13-486f-a866-2cac402dc589\"}\n[2026-05-28 08:32:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"35f98b1b-7b16-4e79-a420-7e9818097d24\",\"trace_id\":\"d66deb58-fa13-486f-a866-2cac402dc589\"}\n[2026-05-28 08:32:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"bc6784c1-c46f-4295-be09-87334f4baa39\",\"trace_id\":\"74b00236-4ed0-4464-8b07-99c328ab6461\"}\n[2026-05-28 08:32:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"bc6784c1-c46f-4295-be09-87334f4baa39\",\"trace_id\":\"74b00236-4ed0-4464-8b07-99c328ab6461\"}\n[2026-05-28 08:32:11] local.NOTICE: Monitoring start {\"correlation_id\":\"caf4d1dd-2a52-40f5-834a-f9148f642e83\",\"trace_id\":\"1312bdcc-7e8b-480a-a935-2433fb79dc70\"}\n[2026-05-28 08:32:11] local.NOTICE: Monitoring end {\"correlation_id\":\"caf4d1dd-2a52-40f5-834a-f9148f642e83\",\"trace_id\":\"1312bdcc-7e8b-480a-a935-2433fb79dc70\"}\n[2026-05-28 08:32:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"64d86889-1f0d-4f7d-a1ac-6f56e58e775e\",\"trace_id\":\"b184d66b-49f8-40ec-afbe-2e76e9c7d952\"}\n[2026-05-28 08:32:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"64d86889-1f0d-4f7d-a1ac-6f56e58e775e\",\"trace_id\":\"b184d66b-49f8-40ec-afbe-2e76e9c7d952\"}\n[2026-05-28 08:32:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"8e6dd4bc-4f44-4fb2-b2ba-9e2f385996ef\",\"trace_id\":\"7767e0ca-37a3-43a5-972e-ea9a1bedea2f\"}\n[2026-05-28 08:32:20] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"8e6dd4bc-4f44-4fb2-b2ba-9e2f385996ef\",\"trace_id\":\"7767e0ca-37a3-43a5-972e-ea9a1bedea2f\"}\n[2026-05-28 08:32:20] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"8e6dd4bc-4f44-4fb2-b2ba-9e2f385996ef\",\"trace_id\":\"7767e0ca-37a3-43a5-972e-ea9a1bedea2f\"}\n[2026-05-28 08:32:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"8e6dd4bc-4f44-4fb2-b2ba-9e2f385996ef\",\"trace_id\":\"7767e0ca-37a3-43a5-972e-ea9a1bedea2f\"}\n[2026-05-28 08:32:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"6750ab25-6dff-4e7b-9f6e-bc7d1fc4221a\",\"trace_id\":\"3db6ce9b-167d-4214-a32c-67c611aa2bbe\"}\n[2026-05-28 08:32:22] local.INFO: Running conference:monitor:count command for activities in (2026-05-28 08:30:00, 2026-05-28 08:32:00] {\"correlation_id\":\"6750ab25-6dff-4e7b-9f6e-bc7d1fc4221a\",\"trace_id\":\"3db6ce9b-167d-4214-a32c-67c611aa2bbe\"}\n[2026-05-28 08:32:22] local.INFO: [conference:monitor:count] No activities found in (2026-05-28 08:30:00, 2026-05-28 08:32:00] {\"correlation_id\":\"6750ab25-6dff-4e7b-9f6e-bc7d1fc4221a\",\"trace_id\":\"3db6ce9b-167d-4214-a32c-67c611aa2bbe\"}\n[2026-05-28 08:32:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"6750ab25-6dff-4e7b-9f6e-bc7d1fc4221a\",\"trace_id\":\"3db6ce9b-167d-4214-a32c-67c611aa2bbe\"}\n[2026-05-28 08:32:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"04510c2c-638c-4687-81d7-b12e76f41df3\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}\n[2026-05-28 08:32:23] local.INFO: [EmailSchedule] STARTING batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"04510c2c-638c-4687-81d7-b12e76f41df3\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}\n[2026-05-28 08:32:23] local.INFO: [EmailSchedule] FINISHED batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"04510c2c-638c-4687-81d7-b12e76f41df3\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}\n[2026-05-28 08:32:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"04510c2c-638c-4687-81d7-b12e76f41df3\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}\n[2026-05-28 08:32:25] local.INFO: [Jiminny\\Jobs\\Mailbox\\CreateBatches] processed 1 inboxes and created 0 batches {\"userId\":null,\"batchSize\":30,\"maxBatches\":1000} {\"correlation_id\":\"e60597ef-aca8-4bda-bb90-18f01e96874d\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}","depth":4,"on_screen":true,"value":"[2026-05-28 08:28:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"73199e23-a066-42ba-b189-2802e0869a44\",\"trace_id\":\"e53672c2-0f50-409d-af25-84ab485c505d\"}\n[2026-05-28 08:28:04] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"73199e23-a066-42ba-b189-2802e0869a44\",\"trace_id\":\"e53672c2-0f50-409d-af25-84ab485c505d\"}\n[2026-05-28 08:28:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"73199e23-a066-42ba-b189-2802e0869a44\",\"trace_id\":\"e53672c2-0f50-409d-af25-84ab485c505d\"}\n[2026-05-28 08:28:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"741b2c4e-6a44-4c46-b9fb-fce017aef225\",\"trace_id\":\"804dc547-eb25-4b32-8d0f-c87019773085\"}\n[2026-05-28 08:28:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"741b2c4e-6a44-4c46-b9fb-fce017aef225\",\"trace_id\":\"804dc547-eb25-4b32-8d0f-c87019773085\"}\n[2026-05-28 08:28:09] local.NOTICE: Monitoring start {\"correlation_id\":\"8ae5c131-edd9-463d-8161-875f4d34320f\",\"trace_id\":\"1b6420c8-ef4e-4566-81b2-688696064648\"}\n[2026-05-28 08:28:09] local.NOTICE: Monitoring end {\"correlation_id\":\"8ae5c131-edd9-463d-8161-875f4d34320f\",\"trace_id\":\"1b6420c8-ef4e-4566-81b2-688696064648\"}\n[2026-05-28 08:28:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"6f5390d3-abe7-4e56-a662-aeed1098941b\",\"trace_id\":\"b57dc2df-2f4d-4d3b-b09a-aa6e61205d5e\"}\n[2026-05-28 08:28:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"6f5390d3-abe7-4e56-a662-aeed1098941b\",\"trace_id\":\"b57dc2df-2f4d-4d3b-b09a-aa6e61205d5e\"}\n[2026-05-28 08:28:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"ba694158-ea28-4ac1-b134-83ac485146e0\",\"trace_id\":\"83a26b74-baa5-407e-9fc2-2b49d65b1c77\"}\n[2026-05-28 08:28:12] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"ba694158-ea28-4ac1-b134-83ac485146e0\",\"trace_id\":\"83a26b74-baa5-407e-9fc2-2b49d65b1c77\"}\n[2026-05-28 08:28:12] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"ba694158-ea28-4ac1-b134-83ac485146e0\",\"trace_id\":\"83a26b74-baa5-407e-9fc2-2b49d65b1c77\"}\n[2026-05-28 08:28:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"ba694158-ea28-4ac1-b134-83ac485146e0\",\"trace_id\":\"83a26b74-baa5-407e-9fc2-2b49d65b1c77\"}\n[2026-05-28 08:28:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"b79833c7-3eab-4eb7-98bb-42359039b8fb\",\"trace_id\":\"a8e159bc-867d-40af-bf7d-1228cf6d4f16\"}\n[2026-05-28 08:28:14] local.INFO: Running conference:monitor:count command for activities in (2026-05-28 08:26:00, 2026-05-28 08:28:00] {\"correlation_id\":\"b79833c7-3eab-4eb7-98bb-42359039b8fb\",\"trace_id\":\"a8e159bc-867d-40af-bf7d-1228cf6d4f16\"}\n[2026-05-28 08:28:14] local.INFO: [conference:monitor:count] No activities found in (2026-05-28 08:26:00, 2026-05-28 08:28:00] {\"correlation_id\":\"b79833c7-3eab-4eb7-98bb-42359039b8fb\",\"trace_id\":\"a8e159bc-867d-40af-bf7d-1228cf6d4f16\"}\n[2026-05-28 08:28:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"b79833c7-3eab-4eb7-98bb-42359039b8fb\",\"trace_id\":\"a8e159bc-867d-40af-bf7d-1228cf6d4f16\"}\n[2026-05-28 08:28:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"d51071d5-ead0-45f0-a07e-e3234074f884\",\"trace_id\":\"77173d9f-596f-405f-ae55-ba117b66455d\"}\n[2026-05-28 08:28:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"calendar:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.NOTICE: Calendar sync start {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"d51071d5-ead0-45f0-a07e-e3234074f884\",\"trace_id\":\"77173d9f-596f-405f-ae55-ba117b66455d\"}\n[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1393,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1393,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1393,\"provider\":\"google\",\"refreshToken\":\"5aa7e2d96b53201cd16fca5d2e4ef3ad03320971fc064781d18aee3ae7b99fbf\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1393,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1393,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1387,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1387,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1387,\"provider\":\"google\",\"refreshToken\":\"8157ac6de94842937194009e9c50e459253600f799dacf6a40755ffdbeb5bba6\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1387,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1387,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1348,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1348,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1348,\"provider\":\"google\",\"refreshToken\":\"9e7d13d3032d0cb1b79d8e95aef01383e8e91eb52ff8ee960c8a0b6b95cd8c73\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1348,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1348,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1361,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1361,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1361,\"provider\":\"google\",\"refreshToken\":\"6c843da199c2b9907445329304fcc4ec5057a4ee748d8299641764395c08e1fd\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1361,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1361,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1310,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1310,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1310,\"provider\":\"google\",\"refreshToken\":\"e34818922c2830a660813a63f6169a4a9a992ae2cccd7dc8dd7796cfdb470ef1\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1310,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1310,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1333,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1333,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1333,\"provider\":\"google\",\"refreshToken\":\"6c902986546d8e8da1dc539b046cdc1d458f519acc972e5b5f1d6a1a295165e0\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1333,\"provider\":\"google\",\"responseBody\":{\"error\":\"unauthorized_client\",\"error_description\":\"Unauthorized\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1333,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1368,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1368,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1368,\"provider\":\"google\",\"refreshToken\":\"d2f128898ff8543bd16b69cfae37896ab85119b0f5ed2b431d739593bb600333\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1368,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1368,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1365,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1365,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1365,\"provider\":\"google\",\"refreshToken\":\"7676e4a9afcd082b413248ab5ec6e487021fec6a9bdf315860a59cefad9caad8\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1365,\"provider\":\"google\",\"responseBody\":{\"error\":\"unauthorized_client\",\"error_description\":\"Unauthorized\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1365,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1364,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1364,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1364,\"provider\":\"google\",\"refreshToken\":\"dd5882ebce76e645292ce33ae74238abbb77c0a4ecc6a2bfe723cad82e72ba8e\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1364,\"provider\":\"google\",\"responseBody\":{\"error\":\"unauthorized_client\",\"error_description\":\"Unauthorized\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1364,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1370,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1370,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1370,\"provider\":\"office\",\"refreshToken\":\"b7ee8035306d0043cea6e00e7c4fe14f745e44074a1194db62a31cdf8b70af3e\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1370,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 41d8db5c-a91f-41a6-9b5c-22a6c99b9100 Correlation ID: 70bc0a6f-1565-4e74-94dc-419d94108fa9 Timestamp: 2026-05-28 08:28:18Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:18Z\\\",\\\"trace_id\\\":\\\"41d8db5c-a91f-41a6-9b5c-22a6c99b9100\\\",\\\"correlation_id\\\":\\\"70bc0a6f-1565-4e74-94dc-419d94108fa9\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1370,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1202,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1202,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1202,\"provider\":\"office\",\"refreshToken\":\"b458799ccc29b21a6e2eb5260fdb63e49ccba21bf942a3973fb63799bd7f0afe\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1202,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: d3d14dfc-1b70-40c4-b9db-fab12f748300 Correlation ID: 4c5f746c-8366-44c1-8733-6877607826db Timestamp: 2026-05-28 08:28:19Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:19Z\\\",\\\"trace_id\\\":\\\"d3d14dfc-1b70-40c4-b9db-fab12f748300\\\",\\\"correlation_id\\\":\\\"4c5f746c-8366-44c1-8733-6877607826db\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1202,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: Calendar sync job dispatched {\"calendar_id\":501} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1300,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1300,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1300,\"provider\":\"google\",\"refreshToken\":\"4b811db0725fd9602a95943519a7da935e2a5065da7d9ebfcb170752e3e1ddb8\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1300,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1300,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1409,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1409,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1409,\"provider\":\"google\",\"refreshToken\":\"e2a3f2d06894894eed1ee87d9db1ace77d4d42ee6e1288a8940ad2c10333b0c4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1409,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1409,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1352,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1352,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1352,\"provider\":\"google\",\"refreshToken\":\"dd4b16b00fdc1216da6b717c02338c073636e29162826b2de6db3f064fc029eb\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1352,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1352,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1296,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1296,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1296,\"provider\":\"office\",\"refreshToken\":\"011ae723c9d800c674e0b4be76f49fc046dac7d501b66c59ef0d9549cfa56ae5\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [Calendar] Processing sync {\"calendarId\":\"a33076c1-8d97-431a-99f0-85c9524e118b\",\"from\":null,\"to\":null,\"delta\":\"CIiFh8TP44kDEIiFh8TP44kDGAUgkZvkzgIokZvkzgI=\",\"last_sync\":\"2024-12-09 07:12:53\",\"dateMode\":\"daily\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"integration-app\",\"crm_owner\":1695,\"team_id\":3143} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1296,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: dd83a147-95bc-407c-8c9b-3c14e7cb7d00 Correlation ID: bb16bae3-b3c4-467e-bd95-4e7ab85364c9 Timestamp: 2026-05-28 08:28:20Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:20Z\\\",\\\"trace_id\\\":\\\"dd83a147-95bc-407c-8c9b-3c14e7cb7d00\\\",\\\"correlation_id\\\":\\\"bb16bae3-b3c4-467e-bd95-4e7ab85364c9\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1296,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":391,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":391,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":391,\"provider\":\"office\",\"refreshToken\":\"00045eebae0f39b34887c6d53f92ae78064f7145e1f4b67754aebd03cfb2d881\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.INFO: [Google Calendar] Failed to watch channel for calendar {\"calendarId\":\"a33076c1-8d97-431a-99f0-85c9524e118b\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:20] local.WARNING: [Calendar] Sync failed {\"calendarId\":\"a33076c1-8d97-431a-99f0-85c9524e118b\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"45e201e4-60d2-407c-ae71-13e4739c0875\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":391,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 587224ad-f597-4371-b2ba-00fcd2da1b00 Correlation ID: 4e752610-95b1-4606-847f-68e00f90be0a Timestamp: 2026-05-28 08:28:21Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:21Z\\\",\\\"trace_id\\\":\\\"587224ad-f597-4371-b2ba-00fcd2da1b00\\\",\\\"correlation_id\\\":\\\"4e752610-95b1-4606-847f-68e00f90be0a\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":391,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1271,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1271,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1271,\"provider\":\"office\",\"refreshToken\":\"118cde2c06993147b07ccaec4cbcd5026a819dea6c71081166a492933e392afb\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1271,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: dd8bf2a7-bc49-43d7-a487-892c51e27600 Correlation ID: 51e3eb6c-c47e-4dd7-91aa-e734fe5b65cf Timestamp: 2026-05-28 08:28:21Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-28 08:28:21Z\\\",\\\"trace_id\\\":\\\"dd8bf2a7-bc49-43d7-a487-892c51e27600\\\",\\\"correlation_id\\\":\\\"51e3eb6c-c47e-4dd7-91aa-e734fe5b65cf\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1271,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1351,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1351,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1351,\"provider\":\"google\",\"refreshToken\":\"4271d15b9e60a606439caddc68337f783e472c85b03dacff14d1b6dfded9051c\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1351,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1351,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1366,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1366,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1366,\"provider\":\"google\",\"refreshToken\":\"ae21385059b2eebfd43f68aecd56eccd702a1aabb6598f1f7ab594ed8af491b4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1366,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1366,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: Calendar sync job dispatched {\"calendar_id\":378} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: Calendar sync job dispatched {\"calendar_id\":504} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.NOTICE: Calendar sync end {\"retrieved_calendars\":31,\"processed_calendars\":3} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"calendar:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"498bfcf1-b82c-466d-8f91-2f3f1cdf980f\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [Calendar] Processing sync {\"calendarId\":\"2676cb6d-f86c-427e-bf78-591e388e3c1e\",\"from\":null,\"to\":null,\"delta\":\"CJ_x49O3jpIDEJ_x49O3jpIDGAUgw67KlwMow67KlwM=\",\"last_sync\":\"2026-01-19 07:48:40\",\"dateMode\":\"daily\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.WARNING: [Pipedrive] Account not connected for user {\"userId\":\"e6538737-e7b4-455f-a37a-3e79b665a220\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":1116,\"sociable_id\":241,\"provider_user_id\":\"19555731\",\"expires\":1779091997,\"refresh_token_expires\":null,\"provider\":\"pipedrive\",\"state\":\"full-refresh\",\"auth_scope\":\"base,deals:full,activities:full,contacts:full,search:read\",\"retry_after\":null,\"created_at\":\"2023-09-08 09:44:29\",\"updated_at\":\"2026-05-18 08:13:32\"}}} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"pipedrive\",\"crm_owner\":241,\"team_id\":19} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"pipedrive\",\"team_id\":19} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"pipedrive\",\"team_id\":19} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.WARNING: [Calendar] CRM disconnected for user so events will not be matched {\"provider\":\"pipedrive\",\"user_id\":241,\"message\":\"Your Pipedrive account has become disconnected. Please login to Jiminny to reconnect.\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [Google Calendar] Failed to watch channel for calendar {\"calendarId\":\"2676cb6d-f86c-427e-bf78-591e388e3c1e\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.WARNING: [Calendar] Sync failed {\"calendarId\":\"2676cb6d-f86c-427e-bf78-591e388e3c1e\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"9436b0cd-f0cc-4ee2-805e-472888fd5928\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [Calendar] Processing sync {\"calendarId\":\"9e8b1a2c-1a8f-42bd-b161-810fc0baf540\",\"from\":null,\"to\":null,\"delta\":\"R0usmcdvmMuZCBYV0hguCBhf4uKqyU9_gdNd-le_nqqau95XAUmZwlIAy2uwtCf5sA67w6NIiDvawUSmVjpTzZO-RsxLdeS-g8Kxy6ODZQxAxafq8AJNx0hJV7T291NUvfaPYqLMv-3je3IdhAPUtXQXkHtYaBAlX_DDBxwc3zYoVVQ8iM9mQkBykdA3sh-KVYPyzi7nK4cZg5Jzpu9tHA.UA7urx3pJyhUhdo_16STIbSNXUrF-qeQVIis9stVUeY\",\"last_sync\":\"2026-05-28 07:44:06\",\"dateMode\":\"daily\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":89,\"team_id\":2} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:28:23] local.INFO: [MS Office Calendar] Skipping delta sync for daily mode {\"calendarId\":\"9e8b1a2c-1a8f-42bd-b161-810fc0baf540\"} {\"correlation_id\":\"82ba6688-7d5c-4789-9154-9918f63e2bfd\",\"trace_id\":\"19e20da3-a204-446a-a01e-568f25ddd9fd\"}\n[2026-05-28 08:29:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"86a65904-a9f8-43c9-b0c3-1e9c8b4b9541\",\"trace_id\":\"800b02ff-3553-46a3-a8c6-c12324a1ce53\"}\n[2026-05-28 08:29:05] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"86a65904-a9f8-43c9-b0c3-1e9c8b4b9541\",\"trace_id\":\"800b02ff-3553-46a3-a8c6-c12324a1ce53\"}\n[2026-05-28 08:29:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"86a65904-a9f8-43c9-b0c3-1e9c8b4b9541\",\"trace_id\":\"800b02ff-3553-46a3-a8c6-c12324a1ce53\"}\n[2026-05-28 08:29:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"e5162656-5b49-4857-9917-f0cf3ddffe27\",\"trace_id\":\"a3a53cc5-596d-474c-b9c4-f6c5f7ebdfd0\"}\n[2026-05-28 08:29:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"e5162656-5b49-4857-9917-f0cf3ddffe27\",\"trace_id\":\"a3a53cc5-596d-474c-b9c4-f6c5f7ebdfd0\"}\n[2026-05-28 08:29:09] local.NOTICE: Monitoring start {\"correlation_id\":\"f559463e-0c12-46df-8b53-0c50cf4aa3eb\",\"trace_id\":\"5a09aee9-5f75-4bfa-93e4-df0ff76f2326\"}\n[2026-05-28 08:29:09] local.NOTICE: Monitoring end {\"correlation_id\":\"f559463e-0c12-46df-8b53-0c50cf4aa3eb\",\"trace_id\":\"5a09aee9-5f75-4bfa-93e4-df0ff76f2326\"}\n[2026-05-28 08:29:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"9b1cc2f1-0c8a-4aa0-a9e8-57ac879839e4\",\"trace_id\":\"d69dd133-b5f0-4568-81ef-9cce3d1c5c9e\"}\n[2026-05-28 08:29:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"9b1cc2f1-0c8a-4aa0-a9e8-57ac879839e4\",\"trace_id\":\"d69dd133-b5f0-4568-81ef-9cce3d1c5c9e\"}\n[2026-05-28 08:29:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"87e10603-9e6f-4d71-97ab-5ba67103e5fd\",\"trace_id\":\"0aae0afb-779f-4999-892d-0188e14b3dcb\"}\n[2026-05-28 08:29:12] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"87e10603-9e6f-4d71-97ab-5ba67103e5fd\",\"trace_id\":\"0aae0afb-779f-4999-892d-0188e14b3dcb\"}\n[2026-05-28 08:29:12] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"87e10603-9e6f-4d71-97ab-5ba67103e5fd\",\"trace_id\":\"0aae0afb-779f-4999-892d-0188e14b3dcb\"}\n[2026-05-28 08:29:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"87e10603-9e6f-4d71-97ab-5ba67103e5fd\",\"trace_id\":\"0aae0afb-779f-4999-892d-0188e14b3dcb\"}\n[2026-05-28 08:30:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"200b132b-d8db-4010-b968-fe5e3fcc42f1\",\"trace_id\":\"7457715a-3b9d-4c35-a499-455c83e925ab\"}\n[2026-05-28 08:30:04] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"200b132b-d8db-4010-b968-fe5e3fcc42f1\",\"trace_id\":\"7457715a-3b9d-4c35-a499-455c83e925ab\"}\n[2026-05-28 08:30:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"200b132b-d8db-4010-b968-fe5e3fcc42f1\",\"trace_id\":\"7457715a-3b9d-4c35-a499-455c83e925ab\"}\n[2026-05-28 08:30:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"a94ef973-dee7-4bdf-99aa-9ff06f5a5561\",\"trace_id\":\"4e37013f-2993-4c71-87d9-560f8f429d27\"}\n[2026-05-28 08:30:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"a94ef973-dee7-4bdf-99aa-9ff06f5a5561\",\"trace_id\":\"4e37013f-2993-4c71-87d9-560f8f429d27\"}\n[2026-05-28 08:30:07] local.NOTICE: Monitoring start {\"correlation_id\":\"691e7103-784d-4b4a-8036-f3c624a186db\",\"trace_id\":\"991dd947-ed80-4080-8769-8ee7efc4e6a4\"}\n[2026-05-28 08:30:07] local.NOTICE: Monitoring end {\"correlation_id\":\"691e7103-784d-4b4a-8036-f3c624a186db\",\"trace_id\":\"991dd947-ed80-4080-8769-8ee7efc4e6a4\"}\n[2026-05-28 08:30:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"00cf8914-d440-4826-a079-ee4586e76c62\",\"trace_id\":\"d77009ee-8d7b-44ae-bb21-2080b6d48c6c\"}\n[2026-05-28 08:30:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"00cf8914-d440-4826-a079-ee4586e76c62\",\"trace_id\":\"d77009ee-8d7b-44ae-bb21-2080b6d48c6c\"}\n[2026-05-28 08:30:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"7c9550d0-42ed-4b1d-b5b3-7dca67f743ec\",\"trace_id\":\"84177853-9530-4b1e-bde6-3dc0c71883ee\"}\n[2026-05-28 08:30:10] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"7c9550d0-42ed-4b1d-b5b3-7dca67f743ec\",\"trace_id\":\"84177853-9530-4b1e-bde6-3dc0c71883ee\"}\n[2026-05-28 08:30:10] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"7c9550d0-42ed-4b1d-b5b3-7dca67f743ec\",\"trace_id\":\"84177853-9530-4b1e-bde6-3dc0c71883ee\"}\n[2026-05-28 08:30:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"7c9550d0-42ed-4b1d-b5b3-7dca67f743ec\",\"trace_id\":\"84177853-9530-4b1e-bde6-3dc0c71883ee\"}\n[2026-05-28 08:30:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"85cc6c92-262b-45c5-bbcc-4a084137fde3\",\"trace_id\":\"058bc9a3-67af-49b6-a87c-8a0a0bc0c47a\"}\n[2026-05-28 08:30:12] local.INFO: Running conference:monitor:count command for activities in (2026-05-28 08:28:00, 2026-05-28 08:30:00] {\"correlation_id\":\"85cc6c92-262b-45c5-bbcc-4a084137fde3\",\"trace_id\":\"058bc9a3-67af-49b6-a87c-8a0a0bc0c47a\"}\n[2026-05-28 08:30:12] local.INFO: [conference:monitor:count] No activities found in (2026-05-28 08:28:00, 2026-05-28 08:30:00] {\"correlation_id\":\"85cc6c92-262b-45c5-bbcc-4a084137fde3\",\"trace_id\":\"058bc9a3-67af-49b6-a87c-8a0a0bc0c47a\"}\n[2026-05-28 08:30:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"85cc6c92-262b-45c5-bbcc-4a084137fde3\",\"trace_id\":\"058bc9a3-67af-49b6-a87c-8a0a0bc0c47a\"}\n[2026-05-28 08:30:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"5083d024-d669-4c6a-bde3-ce084d6a628c\",\"trace_id\":\"83110e1f-4309-4f4a-b8bb-eab5c0ec081e\"}\n[2026-05-28 08:30:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"5083d024-d669-4c6a-bde3-ce084d6a628c\",\"trace_id\":\"83110e1f-4309-4f4a-b8bb-eab5c0ec081e\"}\n[2026-05-28 08:30:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"bc529b16-9502-4df3-b2c0-c63fcf977ed5\",\"trace_id\":\"9dd5d6d0-4cc5-454c-a0c8-0e72b69eeb29\"}\n[2026-05-28 08:30:15] local.INFO: [TextRelayService] Starting sync {\"mailbox\":\"catch-all@txt.staging.jiminny.com\",\"expected_alias\":\"catch-all\",\"expected_host\":\"txt.staging.jiminny.com\"} {\"correlation_id\":\"bc529b16-9502-4df3-b2c0-c63fcf977ed5\",\"trace_id\":\"9dd5d6d0-4cc5-454c-a0c8-0e72b69eeb29\"}\n[2026-05-28 08:30:15] local.INFO: [TextRelayService] Sync completed {\"mailbox\":\"catch-all@txt.staging.jiminny.com\",\"messages_processed\":0,\"message_ids\":[]} {\"correlation_id\":\"bc529b16-9502-4df3-b2c0-c63fcf977ed5\",\"trace_id\":\"9dd5d6d0-4cc5-454c-a0c8-0e72b69eeb29\"}\n[2026-05-28 08:30:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"bc529b16-9502-4df3-b2c0-c63fcf977ed5\",\"trace_id\":\"9dd5d6d0-4cc5-454c-a0c8-0e72b69eeb29\"}\n[2026-05-28 08:30:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"b655bca8-effa-420b-8686-95ba96f27085\",\"trace_id\":\"b1f43a19-c7ad-428e-9933-4e509b5f0055\"}\n[2026-05-28 08:30:18] local.INFO: Running pre-meeting notification command {\"correlation_id\":\"b655bca8-effa-420b-8686-95ba96f27085\",\"trace_id\":\"b1f43a19-c7ad-428e-9933-4e509b5f0055\"}\n[2026-05-28 08:30:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"b655bca8-effa-420b-8686-95ba96f27085\",\"trace_id\":\"b1f43a19-c7ad-428e-9933-4e509b5f0055\"}\n[2026-05-28 08:30:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"5a8493c4-3ef7-4453-98b7-f32225d453fe\",\"trace_id\":\"056f1aea-8825-4e2c-8239-7804086e504e\"}\n[2026-05-28 08:30:20] local.INFO: Running conference:monitor:start command for activities in (2026-05-28 08:20:00, 2026-05-28 08:25:00] {\"correlation_id\":\"5a8493c4-3ef7-4453-98b7-f32225d453fe\",\"trace_id\":\"056f1aea-8825-4e2c-8239-7804086e504e\"}\n[2026-05-28 08:30:20] local.INFO: [conference:monitor:start] No activities found in (2026-05-28 08:20:00, 2026-05-28 08:25:00] {\"correlation_id\":\"5a8493c4-3ef7-4453-98b7-f32225d453fe\",\"trace_id\":\"056f1aea-8825-4e2c-8239-7804086e504e\"}\n[2026-05-28 08:30:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"5a8493c4-3ef7-4453-98b7-f32225d453fe\",\"trace_id\":\"056f1aea-8825-4e2c-8239-7804086e504e\"}\n[2026-05-28 08:30:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"18a2aed9-1aae-4b10-a7fa-f75a147db499\",\"trace_id\":\"fff0c9b2-1c60-4402-b30a-2f41d9b45db3\"}\n[2026-05-28 08:30:22] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesEnded {\"from\":\"08:25\",\"to\":\"08:30\"} {\"correlation_id\":\"18a2aed9-1aae-4b10-a7fa-f75a147db499\",\"trace_id\":\"fff0c9b2-1c60-4402-b30a-2f41d9b45db3\"}\n[2026-05-28 08:30:22] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesWithUnfinishedSession {\"from\":\"22:20\",\"to\":\"22:25\"} {\"correlation_id\":\"18a2aed9-1aae-4b10-a7fa-f75a147db499\",\"trace_id\":\"fff0c9b2-1c60-4402-b30a-2f41d9b45db3\"}\n[2026-05-28 08:30:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"18a2aed9-1aae-4b10-a7fa-f75a147db499\",\"trace_id\":\"fff0c9b2-1c60-4402-b30a-2f41d9b45db3\"}\n[2026-05-28 08:30:23] local.NOTICE: Repairing HubSpot tokens start {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:23] local.INFO: Trying to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:23] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:23] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":59,\"provider\":\"hubspot\",\"refreshToken\":\"97b78f6e2cc49965c00c2492b602b02708b1392551e6b3f113fbaa48992af90b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:26] local.ERROR: Failed to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:26] local.INFO: Trying to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:26] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:26] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":306,\"provider\":\"hubspot\",\"refreshToken\":\"6fa6aa8cc641d131231acc3470f5c03cb3b07b2e580fb18f8acb3b1dbb72549b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.ERROR: Failed to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.INFO: Trying to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1372,\"provider\":\"hubspot\",\"refreshToken\":\"9aa73948c761da29dce46c177cf9aee1fde483a44169ca38723f9f0597d7a8c4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.ERROR: Failed to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:27] local.NOTICE: Repairing HubSpot tokens end {\"total\":3,\"fixed\":0,\"failed\":3} {\"correlation_id\":\"338516a2-06f3-41cf-8f11-0d2c8a0b2a29\",\"trace_id\":\"58fc6994-1c77-429c-8c16-14c4bd8f57c4\"}\n[2026-05-28 08:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"jiminny:transcription:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"f73071c7-8696-459f-8aff-e61a7c6b30e6\",\"trace_id\":\"d72fc2ce-5064-4877-b401-10891378e1bc\"}\n[2026-05-28 08:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"720d5c87-3d13-4193-87c9-efb8dc6df7c8\",\"trace_id\":\"a9d9c9fe-db29-44a1-a5f6-1905d48dde90\"}\n[2026-05-28 08:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"jiminny:transcription:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"f73071c7-8696-459f-8aff-e61a7c6b30e6\",\"trace_id\":\"d72fc2ce-5064-4877-b401-10891378e1bc\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Command] Starting polling service {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] Service starting {\"memory_limit\":\"256M\",\"max_execution_time\":\"0\",\"initial_memory_mb\":62.0} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] Acquired polling lock {\"expires_at\":\"2026-05-28T08:32:33.444809Z\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"720d5c87-3d13-4193-87c9-efb8dc6df7c8\",\"trace_id\":\"a9d9c9fe-db29-44a1-a5f6-1905d48dde90\"}\n[2026-05-28 08:30:33] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:35] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:reset-governor\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"c692a62b-3b1a-4ff3-b965-388a7d12f619\",\"trace_id\":\"d1bdfdec-73bd-499f-a31e-b25a864da976\"}\n[2026-05-28 08:30:35] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:reset-governor\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"c692a62b-3b1a-4ff3-b965-388a7d12f619\",\"trace_id\":\"d1bdfdec-73bd-499f-a31e-b25a864da976\"}\n[2026-05-28 08:30:38] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:38] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:38] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:39] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814238,\"provider\":\"twilio-flex\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814239,\"provider\":\"xant\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814240,\"provider\":\"apollo\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814241,\"provider\":\"groove\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814242,\"provider\":\"twilio-video\",\"team\":\"jiminny\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Dispatching activity sync job {\"import_id\":814243,\"provider\":\"hubspot\",\"team\":\"hubspot\"} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:39] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"c6f2bef5-da3d-4403-84b7-84c355175282\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:fail-stalled\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"f6d797df-5275-4cf1-8ddd-300c125df8da\",\"trace_id\":\"2b46c31f-aced-4324-a70a-6395f0a72618\"}\n[2026-05-28 08:30:42] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:fail-stalled\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"f6d797df-5275-4cf1-8ddd-300c125df8da\",\"trace_id\":\"2b46c31f-aced-4324-a70a-6395f0a72618\"}\n[2026-05-28 08:30:42] local.WARNING: [Salesforce] Account not connected for user {\"userId\":\"cdf8b554-d951-4758-bc2b-c1b85d1cd0b9\",\"account\":null} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"salesforce\",\"crm_owner\":3,\"team_id\":1} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [CrmOwnerResolver] TeamMember found with active crm connection {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1194,\"provider\":\"twilio-flex\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1194,\"provider\":\"twilio-flex\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.INFO: [SyncActivity] Start {\"import_id\":814238,\"provider\":\"twilio-flex\",\"provider_id\":317,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:42] local.NOTICE: [TwilioFlex] Calls import start {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.ALERT: [SyncActivity] Failed {\"import_id\":814238,\"provider\":\"twilio-flex\",\"provider_id\":317,\"team\":\"jiminny\",\"team_id\":1,\"reason\":\"[HTTP 401] Unable to fetch page: Authenticate\",\"file\":\"/home/jiminny/vendor/twilio/sdk/src/Twilio/Page.php\",\"line\":60} {\"correlation_id\":\"d90e1584-bf02-4654-b950-685da6f49697\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [SyncActivity] Start {\"import_id\":814239,\"provider\":\"xant\",\"provider_id\":161,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [Salesforce] Performing query {\"query\":\"\n SELECT Playbooks_Call_Date__c,Playbooks_Call_Recording__c,CreatedDate,TaskSubtype,CallType,CallDurationInSeconds,Id,OwnerId,WhoId,WhatId,Priority,ActivityDate,Subject,Description,Status,Type\n FROM Task\n WHERE IsDeleted = false\n AND LastModifiedDate >= :from\n AND LastModifiedDate <= :to\n ORDER BY LastModifiedDate ASC\n LIMIT :limit\",\"params\":{\"from\":\"2026-05-28T08:14:00Z\",\"to\":\"2026-05-28T08:30:00Z\",\"ownerId\":null,\"subType\":null,\"limit\":5000}} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:43] local.INFO: [Salesforce] Sending request {\"endpoint\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=%0A++++++++++++SELECT+Playbooks_Call_Date__c%2CPlaybooks_Call_Recording__c%2CCreatedDate%2CTaskSubtype%2CCallType%2CCallDurationInSeconds%2CId%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%0A++++++++++++++FROM+Task%0A+++++++++++++WHERE+IsDeleted+%3D+false%0A+++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A+++++++++++++++AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z%0A++++++++++ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000 GET\",\"team_id\":1} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:44] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:44] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:44] local.INFO: [Xant (InsideSales)] No calls found. {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] End {\"import_id\":814239,\"provider\":\"xant\",\"provider_id\":161,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Memory usage {\"import_id\":814239,\"provider\":\"xant\",\"provider_id\":161,\"team\":\"jiminny\",\"team_id\":1,\"memory_usage\":24080216,\"memory_real_usage\":65011712,\"pid\":21708} {\"correlation_id\":\"664afeb1-65f0-4713-918d-c7644e36eda4\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Start {\"import_id\":814240,\"provider\":\"apollo\",\"provider_id\":441,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Performing query {\"query\":\"\n SELECT AccountId,CreatedDate,TaskSubtype,CallType,Id,OwnerId,WhoId,WhatId,Priority,ActivityDate,Subject,Description,Status,Type\n FROM Task\n WHERE IsDeleted = false\n AND LastModifiedDate >= :from\n AND LastModifiedDate <= :to\n ORDER BY LastModifiedDate ASC\n LIMIT :limit\",\"params\":{\"from\":\"2026-05-28T08:14:00Z\",\"to\":\"2026-05-28T08:30:00Z\",\"ownerId\":null,\"subType\":null,\"limit\":5000}} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Sending request {\"endpoint\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=%0A++++++++++++SELECT+AccountId%2CCreatedDate%2CTaskSubtype%2CCallType%2CId%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%0A++++++++++++++FROM+Task%0A+++++++++++++WHERE+IsDeleted+%3D+false%0A+++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A+++++++++++++++AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z%0A++++++++++ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000 GET\",\"team_id\":1} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Apollo] No calls found. {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] End {\"import_id\":814240,\"provider\":\"apollo\",\"provider_id\":441,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Memory usage {\"import_id\":814240,\"provider\":\"apollo\",\"provider_id\":441,\"team\":\"jiminny\",\"team_id\":1,\"memory_usage\":24242184,\"memory_real_usage\":65011712,\"pid\":21708} {\"correlation_id\":\"82a57baa-c1eb-42dc-b082-fd7d3913c037\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Start {\"import_id\":814241,\"provider\":\"groove\",\"provider_id\":228,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Performing query {\"query\":\"\n SELECT call_recording_url__c,TaskSubtype,CreatedDate,CallType,CallDurationInSeconds,Id,OwnerId,WhoId,WhatId,Priority,ActivityDate,Subject,Description,Status,Type\n FROM Task\n WHERE IsDeleted = false\n AND LastModifiedDate >= :from\n AND LastModifiedDate <= :to\n ORDER BY LastModifiedDate ASC\n LIMIT :limit\",\"params\":{\"from\":\"2026-05-28T08:14:00Z\",\"to\":\"2026-05-28T08:30:00Z\",\"ownerId\":null,\"subType\":null,\"limit\":5000}} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Sending request {\"endpoint\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=%0A++++++++++++SELECT+call_recording_url__c%2CTaskSubtype%2CCreatedDate%2CCallType%2CCallDurationInSeconds%2CId%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%0A++++++++++++++FROM+Task%0A+++++++++++++WHERE+IsDeleted+%3D+false%0A+++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A+++++++++++++++AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z%0A++++++++++ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000 GET\",\"team_id\":1} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"b2b37795-cfa8-472a-b681-322ce27c0e08\",\"trace_id\":\"605e54f2-d4f9-4683-b3fd-6c1c23e691b7\"}\n[2026-05-28 08:30:44] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"b2b37795-cfa8-472a-b681-322ce27c0e08\",\"trace_id\":\"605e54f2-d4f9-4683-b3fd-6c1c23e691b7\"}\n[2026-05-28 08:30:44] local.ERROR: [Salesforce] Request exception [400] \nSELECT call_recording_url__c,TaskSubtype\n ^\nERROR at Row:1:Column:8\nNo such column 'call_recording_url__c' on entity 'Task'. If you are attempting to use a custom field, be sure to append the '__c' after the custom field name. Please reference your WSDL or the describe call for the appropriate names. {\"url\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=%0A++++++++++++SELECT+call_recording_url__c%2CTaskSubtype%2CCreatedDate%2CCallType%2CCallDurationInSeconds%2CId%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%0A++++++++++++++FROM+Task%0A+++++++++++++WHERE+IsDeleted+%3D+false%0A+++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A+++++++++++++++AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z%0A++++++++++ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000\",\"data\":{\"headers\":{\"Authorization\":\"Bearer 00D2g0000008hH4!AQEAQHWUK6nshi8dSCX9CJphxkVivcv_TK98TLOckVy4i0Z1gQfAoRRuH2LVwDXDkbTPs80wvQjczjAlOz0UEtbHoORBLi2u\"}},\"response\":{\"GuzzleHttp\\\\Psr7\\\\Stream\":\"[{\\\"message\\\":\\\"\\\\nSELECT call_recording_url__c,TaskSubtype\\\\n ^\\\\nERROR at Row:1:Column:8\\\\nNo such column 'call_recording_url__c' on entity 'Task'. If you are attempting to use a custom field, be sure to append the '__c' after the custom field name. Please reference your WSDL or the describe call for the appropriate names.\\\",\\\"errorCode\\\":\\\"INVALID_FIELD\\\"}]\"},\"fields\":[]} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.ALERT: [SyncActivity] Failed {\"import_id\":814241,\"provider\":\"groove\",\"provider_id\":228,\"team\":\"jiminny\",\"team_id\":1,\"reason\":\"\nSELECT call_recording_url__c,TaskSubtype\n ^\nERROR at Row:1:Column:8\nNo such column 'call_recording_url__c' on entity 'Task'. If you are attempting to use a custom field, be sure to append the '__c' after the custom field name. Please reference your WSDL or the describe call for the appropriate names.\",\"file\":\"/home/jiminny/app/Services/Crm/Salesforce/Client.php\",\"line\":564} {\"correlation_id\":\"db0b2bb2-4954-4403-80fd-0f02be18b0fb\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"salesforce\",\"crm_owner\":143,\"team_id\":1} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1500,\"provider\":\"salesforce\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [SyncActivity] Start {\"import_id\":814242,\"provider\":\"twilio-video\",\"provider_id\":243,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Performing query {\"query\":\"SELECT Id,OwnerId,WhoId,WhatId,Priority,ActivityDate,Subject,Description,Status,Type,twilio_call_sid__c,Lead_UUID__c,Opportunity__c\n FROM Task\n WHERE Type = 'Video'\n AND isClosed = true\n AND IsDeleted = false\n AND LastModifiedDate >= :from\n AND twilio_call_sid__c != NULL AND LastModifiedDate <= :to ORDER BY LastModifiedDate ASC\n LIMIT :limit\",\"params\":{\"from\":\"2026-05-28T08:14:00Z\",\"to\":\"2026-05-28T08:30:00Z\",\"ownerId\":null,\"subType\":null,\"limit\":5000}} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:44] local.INFO: [Salesforce] Sending request {\"endpoint\":\"https://jiminny--stagingenv.sandbox.my.salesforce.com/services/data/v50.0/query/?q=SELECT+Id%2COwnerId%2CWhoId%2CWhatId%2CPriority%2CActivityDate%2CSubject%2CDescription%2CStatus%2CType%2Ctwilio_call_sid__c%2CLead_UUID__c%2COpportunity__c%0A++++++++++++++FROM+Task%0A++++++++++++WHERE+Type+%3D+%27Video%27%0A++++++++++++++AND+isClosed+%3D+true%0A++++++++++++++AND+IsDeleted+%3D+false%0A++++++++++++++AND+LastModifiedDate+%3E%3D+2026-05-28T08%3A14%3A00Z%0A++++++++++++++AND+twilio_call_sid__c+%21%3D+NULL+AND+LastModifiedDate+%3C%3D+2026-05-28T08%3A30%3A00Z+ORDER+BY+LastModifiedDate+ASC%0A+++++++++++++LIMIT+5000 GET\",\"team_id\":1} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [Twilio Video] No calls found. {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] End {\"import_id\":814242,\"provider\":\"twilio-video\",\"provider_id\":243,\"team\":\"jiminny\",\"team_id\":1} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] Memory usage {\"import_id\":814242,\"provider\":\"twilio-video\",\"provider_id\":243,\"team\":\"jiminny\",\"team_id\":1,\"memory_usage\":24634032,\"memory_real_usage\":65011712,\"pid\":21708} {\"correlation_id\":\"0b355e21-99f2-41eb-8157-fe7cd227fa58\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":89,\"team_id\":2} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":408,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":408,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] Start {\"import_id\":814243,\"provider\":\"hubspot\",\"provider_id\":31,\"team\":\"hubspot\",\"team_id\":2} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [HubSpot] Search calls for period {\"from\":\"2026-05-28 08:14:00\",\"to\":\"2026-05-28 08:30:00\"} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] End {\"import_id\":814243,\"provider\":\"hubspot\",\"provider_id\":31,\"team\":\"hubspot\",\"team_id\":2} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:45] local.INFO: [SyncActivity] Memory usage {\"import_id\":814243,\"provider\":\"hubspot\",\"provider_id\":31,\"team\":\"hubspot\",\"team_id\":2,\"memory_usage\":24947696,\"memory_real_usage\":65011712,\"pid\":21708} {\"correlation_id\":\"4d0058c7-c318-4aea-82c0-403eadc12ccc\",\"trace_id\":\"d36c89c2-6acf-4497-b03c-93e5a090ea28\"}\n[2026-05-28 08:30:46] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"nudges:send\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"f3e257b6-82bb-440c-bf76-855ac528e4e8\",\"trace_id\":\"f8a31218-7290-45ac-8fe1-ffb1b8527521\"}\n[2026-05-28 08:30:46] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"nudges:send\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"f3e257b6-82bb-440c-bf76-855ac528e4e8\",\"trace_id\":\"f8a31218-7290-45ac-8fe1-ffb1b8527521\"}\n[2026-05-28 08:30:50] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"jiminny:playlists:normalize-sort\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"a64b1836-79a1-41da-a4b0-bc0a9703a94b\",\"trace_id\":\"c53faedc-a7a7-41b7-8e51-e84dc2755d79\"}\n[2026-05-28 08:30:50] local.INFO: [Jiminny\\Component\\Playlist\\Command\\NormalizeSortCommand::handle] starting. {\"playlists\":[]} {\"correlation_id\":\"a64b1836-79a1-41da-a4b0-bc0a9703a94b\",\"trace_id\":\"c53faedc-a7a7-41b7-8e51-e84dc2755d79\"}\n[2026-05-28 08:30:50] local.INFO: [Jiminny\\Component\\Playlist\\Command\\NormalizeSortCommand::handle] finished. {\"normalizedPlaylists\":[],\"deletedPlaylists\":[]} {\"correlation_id\":\"a64b1836-79a1-41da-a4b0-bc0a9703a94b\",\"trace_id\":\"c53faedc-a7a7-41b7-8e51-e84dc2755d79\"}\n[2026-05-28 08:30:50] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"jiminny:playlists:normalize-sort\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"a64b1836-79a1-41da-a4b0-bc0a9703a94b\",\"trace_id\":\"c53faedc-a7a7-41b7-8e51-e84dc2755d79\"}\n[2026-05-28 08:30:59] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:59] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:30:59] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"41db30ba-33c5-46f1-b8bd-5d9e86a70d12\",\"trace_id\":\"a5e2028d-ca41-4ba1-9ddd-a246f83ef4cc\"}\n[2026-05-28 08:31:07] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"41db30ba-33c5-46f1-b8bd-5d9e86a70d12\",\"trace_id\":\"a5e2028d-ca41-4ba1-9ddd-a246f83ef4cc\"}\n[2026-05-28 08:31:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"41db30ba-33c5-46f1-b8bd-5d9e86a70d12\",\"trace_id\":\"a5e2028d-ca41-4ba1-9ddd-a246f83ef4cc\"}\n[2026-05-28 08:31:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"f6ed0a05-caa1-4cb6-ae83-63f44ae4e0d6\",\"trace_id\":\"16cd898d-57a1-4b74-90d1-f9223bbd8d7a\"}\n[2026-05-28 08:31:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"f6ed0a05-caa1-4cb6-ae83-63f44ae4e0d6\",\"trace_id\":\"16cd898d-57a1-4b74-90d1-f9223bbd8d7a\"}\n[2026-05-28 08:31:15] local.NOTICE: Monitoring start {\"correlation_id\":\"cdf384ea-4f59-4411-8ebf-efc299e4a1c8\",\"trace_id\":\"b069d3c8-2f77-4698-bd53-97de373652e8\"}\n[2026-05-28 08:31:15] local.NOTICE: Monitoring end {\"correlation_id\":\"cdf384ea-4f59-4411-8ebf-efc299e4a1c8\",\"trace_id\":\"b069d3c8-2f77-4698-bd53-97de373652e8\"}\n[2026-05-28 08:31:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"940a264b-4aee-40a0-a527-e101ea555a38\",\"trace_id\":\"cd9169ad-4c1e-452d-b7cb-66005aae4dc8\"}\n[2026-05-28 08:31:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"940a264b-4aee-40a0-a527-e101ea555a38\",\"trace_id\":\"cd9169ad-4c1e-452d-b7cb-66005aae4dc8\"}\n[2026-05-28 08:31:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"b798f381-71f2-4c51-a135-f91f09330cfd\",\"trace_id\":\"b44ed325-23f7-4f8b-a447-4c8d0ee99d01\"}\n[2026-05-28 08:31:23] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"b798f381-71f2-4c51-a135-f91f09330cfd\",\"trace_id\":\"b44ed325-23f7-4f8b-a447-4c8d0ee99d01\"}\n[2026-05-28 08:31:24] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"b798f381-71f2-4c51-a135-f91f09330cfd\",\"trace_id\":\"b44ed325-23f7-4f8b-a447-4c8d0ee99d01\"}\n[2026-05-28 08:31:24] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"b798f381-71f2-4c51-a135-f91f09330cfd\",\"trace_id\":\"b44ed325-23f7-4f8b-a447-4c8d0ee99d01\"}\n[2026-05-28 08:31:27] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"2d631328-f2b9-44f3-83d3-613b7b9b9ddc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:27] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"2d631328-f2b9-44f3-83d3-613b7b9b9ddc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"usage\":22563136,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [HubSpot] Syncing opportunities using strategy: lastModified {\"team\":2} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.4,\"average_seconds_per_request\":0.4} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [HubSpot] Synced opportunities {\"team\":2,\"strategies\":\"lastModified\",\"sync_count\":0,\"total\":0,\"last_synced_id\":null,\"duration_ms\":432.6} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"provider\":\"hubspot\",\"status\":\"completed\",\"duration_ms\":543.02,\"usage\":22983640,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"5b5669c7-bb21-4c59-97e6-edafd6520cc4\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"usage\":22961848,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"2ac0447f-3c8c-4ce0-baeb-b63ddb76fa9b\",\"account\":null} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":130,\"team_id\":42} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":23.85,\"usage\":23024000,\"real_usage\":65011712,\"pid\":21703,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"32799697-dd65-4ad4-b1d1-cd553c4510f8\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"usage\":22984760,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"33e34a7a-1c02-4f04-87ac-22c3a385e6e3\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":306,\"sociable_id\":109,\"provider_user_id\":\"11348452\",\"expires\":1701077403,\"refresh_token_expires\":null,\"provider\":\"hubspot\",\"state\":\"full-refresh\",\"auth_scope\":null,\"retry_after\":null,\"created_at\":\"2020-09-01 16:59:04\",\"updated_at\":\"2023-11-27 09:30:03\"}}} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":109,\"team_id\":29} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:28] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":14.98,\"usage\":23047624,\"real_usage\":65011712,\"pid\":21703,\"reason\":\"Your HubSpot account has become disconnected. Please login to Jiminny to reconnect.\"} {\"correlation_id\":\"0732b08b-2bf7-4f5b-93b6-9b2889269535\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal Polling] Service ending {\"runtime_seconds\":56,\"total_cycles\":5,\"files_downloaded\":0,\"empty_files\":0,\"other_portal_skipped\":0,\"total_events\":0,\"events_per_file\":0,\"avg_api_ms\":192.1,\"avg_download_ms\":0.0,\"avg_transform_ms\":0.0,\"avg_process_ms\":0.0,\"peak_memory_mb\":99.88} {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [HubSpot Journal Polling] Released polling lock {\"correlation_id\":\"69a84dc3-5ad9-4eb1-8057-5b1e80de395e\",\"trace_id\":\"5e8af621-8c17-4344-bc12-18da6b71d516\"}\n[2026-05-28 08:31:29] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"usage\":23005136,\"real_usage\":65011712,\"pid\":21703} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"71e3aac5-fb66-47c5-a236-2d051ae3e319\",\"account\":null} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":256,\"team_id\":49} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:31:29] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":34.51,\"usage\":23021248,\"real_usage\":65011712,\"pid\":21703,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"4f83a1ac-418f-4f49-8377-328b614306fc\",\"trace_id\":\"aa1cae8a-acff-4b75-8a3d-e4f9ed33c815\"}\n[2026-05-28 08:32:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"35f98b1b-7b16-4e79-a420-7e9818097d24\",\"trace_id\":\"d66deb58-fa13-486f-a866-2cac402dc589\"}\n[2026-05-28 08:32:06] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {\"count\":0} {\"correlation_id\":\"35f98b1b-7b16-4e79-a420-7e9818097d24\",\"trace_id\":\"d66deb58-fa13-486f-a866-2cac402dc589\"}\n[2026-05-28 08:32:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"35f98b1b-7b16-4e79-a420-7e9818097d24\",\"trace_id\":\"d66deb58-fa13-486f-a866-2cac402dc589\"}\n[2026-05-28 08:32:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"bc6784c1-c46f-4295-be09-87334f4baa39\",\"trace_id\":\"74b00236-4ed0-4464-8b07-99c328ab6461\"}\n[2026-05-28 08:32:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"bc6784c1-c46f-4295-be09-87334f4baa39\",\"trace_id\":\"74b00236-4ed0-4464-8b07-99c328ab6461\"}\n[2026-05-28 08:32:11] local.NOTICE: Monitoring start {\"correlation_id\":\"caf4d1dd-2a52-40f5-834a-f9148f642e83\",\"trace_id\":\"1312bdcc-7e8b-480a-a935-2433fb79dc70\"}\n[2026-05-28 08:32:11] local.NOTICE: Monitoring end {\"correlation_id\":\"caf4d1dd-2a52-40f5-834a-f9148f642e83\",\"trace_id\":\"1312bdcc-7e8b-480a-a935-2433fb79dc70\"}\n[2026-05-28 08:32:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"64d86889-1f0d-4f7d-a1ac-6f56e58e775e\",\"trace_id\":\"b184d66b-49f8-40ec-afbe-2e76e9c7d952\"}\n[2026-05-28 08:32:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"64d86889-1f0d-4f7d-a1ac-6f56e58e775e\",\"trace_id\":\"b184d66b-49f8-40ec-afbe-2e76e9c7d952\"}\n[2026-05-28 08:32:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"8e6dd4bc-4f44-4fb2-b2ba-9e2f385996ef\",\"trace_id\":\"7767e0ca-37a3-43a5-972e-ea9a1bedea2f\"}\n[2026-05-28 08:32:20] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"8e6dd4bc-4f44-4fb2-b2ba-9e2f385996ef\",\"trace_id\":\"7767e0ca-37a3-43a5-972e-ea9a1bedea2f\"}\n[2026-05-28 08:32:20] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"8e6dd4bc-4f44-4fb2-b2ba-9e2f385996ef\",\"trace_id\":\"7767e0ca-37a3-43a5-972e-ea9a1bedea2f\"}\n[2026-05-28 08:32:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"8e6dd4bc-4f44-4fb2-b2ba-9e2f385996ef\",\"trace_id\":\"7767e0ca-37a3-43a5-972e-ea9a1bedea2f\"}\n[2026-05-28 08:32:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"6750ab25-6dff-4e7b-9f6e-bc7d1fc4221a\",\"trace_id\":\"3db6ce9b-167d-4214-a32c-67c611aa2bbe\"}\n[2026-05-28 08:32:22] local.INFO: Running conference:monitor:count command for activities in (2026-05-28 08:30:00, 2026-05-28 08:32:00] {\"correlation_id\":\"6750ab25-6dff-4e7b-9f6e-bc7d1fc4221a\",\"trace_id\":\"3db6ce9b-167d-4214-a32c-67c611aa2bbe\"}\n[2026-05-28 08:32:22] local.INFO: [conference:monitor:count] No activities found in (2026-05-28 08:30:00, 2026-05-28 08:32:00] {\"correlation_id\":\"6750ab25-6dff-4e7b-9f6e-bc7d1fc4221a\",\"trace_id\":\"3db6ce9b-167d-4214-a32c-67c611aa2bbe\"}\n[2026-05-28 08:32:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"6750ab25-6dff-4e7b-9f6e-bc7d1fc4221a\",\"trace_id\":\"3db6ce9b-167d-4214-a32c-67c611aa2bbe\"}\n[2026-05-28 08:32:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.883} {\"correlation_id\":\"04510c2c-638c-4687-81d7-b12e76f41df3\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}\n[2026-05-28 08:32:23] local.INFO: [EmailSchedule] STARTING batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"04510c2c-638c-4687-81d7-b12e76f41df3\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}\n[2026-05-28 08:32:23] local.INFO: [EmailSchedule] FINISHED batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"04510c2c-638c-4687-81d7-b12e76f41df3\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}\n[2026-05-28 08:32:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.883,\"memoryPeakAfterCommandInMB\":99.883} {\"correlation_id\":\"04510c2c-638c-4687-81d7-b12e76f41df3\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}\n[2026-05-28 08:32:25] local.INFO: [Jiminny\\Jobs\\Mailbox\\CreateBatches] processed 1 inboxes and created 0 batches {\"userId\":null,\"batchSize\":30,\"maxBatches\":1000} {\"correlation_id\":\"e60597ef-aca8-4bda-bb90-18f01e96874d\",\"trace_id\":\"87f0bb69-8fd1-47f1-9c9e-3b0ac3d6bd60\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-914263408208002466
|
3613057122943418527
|
click
|
accessibility
|
NULL
|
2 files committed
JY-20915 fix missing header
text 2 files committed
JY-20915 fix missing header
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
TextRelayServiceTest
Run 'TextRelayServiceTest'
Debug 'TextRelayServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$expectedAlias = config('jiminny.deploy_region') === 'eu' ? 'catch-all-eu' : 'catch-all';
$expectedHost = config('jiminny.google_text_host');
Log::info('[TextRelayService] Starting sync', [
'mailbox' => $mailbox,
'expected_alias' => $expectedAlias,
'expected_host' => $expectedHost,
]);
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded ?? [];
foreach ($messages as $message) {
$messageId = $message->message->id;
if (! $this->isForCurrentEnvironment($service, $mailbox, $messageId, $expectedAlias, $expectedHost)) {
continue;
}
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = new EmailTextRelay($messageId, $relayedText);
$job->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
Log::info('[TextRelayService] Successfully dispatched message', [
'message_id' => $messageId,
'text_relay_id' => $relayedText->id,
'queue' => Constants::QUEUE_EMAILS,
]);
$messageIds[] = $messageId;
}
}
Log::info('[TextRelayService] Sync completed', [
'mailbox' => $mailbox,
'messages_processed' => count($messageIds),
'message_ids' => array_slice($messageIds, 0, 10),
]);
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, (int) $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to fetch Gmail history', [
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = (int) $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
private function isForCurrentEnvironment(
GoogleGmail $service,
string $mailbox,
string $messageId,
string $expectedAlias,
string $expectedHost
): bool {
try {
$message = $service->users_messages->get($mailbox, $messageId);
$headers = $message->getPayload()->getHeaders();
$originalTo = null;
$to = null;
foreach ($headers as $header) {
if ($header->name === 'X-Gm-Original-To') {
$originalTo = $header->value;
} elseif ($header->name === 'To') {
$to = $header->value;
}
}
$recipient = $originalTo ?? $to;
if ($recipient !== null) {
$matches = $this->matchesExpectedRecipient($recipient, $expectedAlias, $expectedHost);
if (! $matches) {
// Sanitize PII by removing plus-tag content for logging
$sanitizedRecipient = explode('+', $recipient)[0];
Log::info('[TextRelayService] Refused message', [
'message_id' => $messageId,
'original_to_sanitized' => $sanitizedRecipient,
]);
}
return $matches;
}
Log::warning('[TextRelayService] Refused message: missing X-Gm-Original-To and To headers', [
'message_id' => $messageId,
]);
} catch (\Exception $e) {
Log::error('[TextRelayService] Failed to inspect message', [
'message_id' => $messageId,
'exception' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return false;
}
private function matchesExpectedRecipient(string $recipient, string $expectedAlias, string $expectedHost): bool
{
$parts = explode('@', $recipient, 2);
if (count($parts) !== 2 || strcasecmp($parts[1], $expectedHost) !== 0) {
return false;
}
$localBase = explode('+', $parts[0], 2)[0];
return strcasecmp($localBase, $expectedAlias) === 0;
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
103
Previous Highlighted Error
Next Highlighted Error
[2026-05-28 08:28:04] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"meeting-bot:schedule-bot","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"73199e23-a066-42ba-b189-2802e0869a44","trace_id":"e53672c2-0f50-409d-af25-84ab485c505d"}
[2026-05-28 08:28:04] local.INFO: [ScheduleBotCommand] Dispatched activities to capture {"count":0} {"correlation_id":"73199e23-a066-42ba-b189-2802e0869a44","trace_id":"e53672c2-0f50-409d-af25-84ab485c505d"}
[2026-05-28 08:28:04] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"meeting-bot:schedule-bot","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"73199e23-a066-42ba-b189-2802e0869a44","trace_id":"e53672c2-0f50-409d-af25-84ab485c505d"}
[2026-05-28 08:28:06] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"dialers:monitor-activities","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"741b2c4e-6a44-4c46-b9fb-fce017aef225","trace_id":"804dc547-eb25-4b32-8d0f-c87019773085"}
[2026-05-28 08:28:06] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"dialers:monitor-activities","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"741b2c4e-6a44-4c46-b9fb-fce017aef225","trace_id":"804dc547-eb25-4b32-8d0f-c87019773085"}
[2026-05-28 08:28:09] local.NOTICE: Monitoring start {"correlation_id":"8ae5c131-edd9-463d-8161-875f4d34320f","trace_id":"1b6420c8-ef4e-4566-81b2-688696064648"}
[2026-05-28 08:28:09] local.NOTICE: Monitoring end {"correlation_id":"8ae5c131-edd9-463d-8161-875f4d34320f","trace_id":"1b6420c8-ef4e-4566-81b2-688696064648"}
[2026-05-28 08:28:10] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"mailbox:skip-lists:refresh","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"6f5390d3-abe7-4e56-a662-aeed1098941b","trace_id":"b57dc2df-2f4d-4d3b-b09a-aa6e61205d5e"}
[2026-05-28 08:28:10] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"mailbox:skip-lists:refresh","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"6f5390d3-abe7-4e56-a662-aeed1098941b","trace_id":"b57dc2df-2f4d-4d3b-b09a-aa6e61205d5e"}
[2026-05-28 08:28:12] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"mailbox:batch:process","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"ba694158-ea28-4ac1-b134-83ac485146e0","trace_id":"83a26b74-baa5-407e-9fc2-2b49d65b1c77"}
[2026-05-28 08:28:12] local.INFO: [EmailSchedule] STARTING batch process {"host":"docker_lamp_1"} {"correlation_id":"ba694158-ea28-4ac1-b134-83ac485146e0","trace_id":"83a26b74-baa5-407e-9fc2-2b49d65b1c77"}
[2026-05-28 08:28:12] local.INFO: [EmailSchedule] FINISHED batch process {"host":"docker_lamp_1","processed":0} {"correlation_id":"ba694158-ea28-4ac1-b134-83ac485146e0","trace_id":"83a26b74-baa5-407e-9fc2-2b49d65b1c77"}
[2026-05-28 08:28:12] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"mailbox:batch:process","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"ba694158-ea28-4ac1-b134-83ac485146e0","trace_id":"83a26b74-baa5-407e-9fc2-2b49d65b1c77"}
[2026-05-28 08:28:14] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"conference:monitor:count","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"b79833c7-3eab-4eb7-98bb-42359039b8fb","trace_id":"a8e159bc-867d-40af-bf7d-1228cf6d4f16"}
[2026-05-28 08:28:14] local.INFO: Running conference:monitor:count command for activities in (2026-05-28 08:26:00, 2026-05-28 08:28:00] {"correlation_id":"b79833c7-3eab-4eb7-98bb-42359039b8fb","trace_id":"a8e159bc-867d-40af-bf7d-1228cf6d4f16"}
[2026-05-28 08:28:14] local.INFO: [conference:monitor:count] No activities found in (2026-05-28 08:26:00, 2026-05-28 08:28:00] {"correlation_id":"b79833c7-3eab-4eb7-98bb-42359039b8fb","trace_id":"a8e159bc-867d-40af-bf7d-1228cf6d4f16"}
[2026-05-28 08:28:14] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"conference:monitor:count","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"b79833c7-3eab-4eb7-98bb-42359039b8fb","trace_id":"a8e159bc-867d-40af-bf7d-1228cf6d4f16"}
[2026-05-28 08:28:16] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"mailbox:batch:retry-failed","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"d51071d5-ead0-45f0-a07e-e3234074f884","trace_id":"77173d9f-596f-405f-ae55-ba117b66455d"}
[2026-05-28 08:28:16] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"calendar:sync","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.883} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.NOTICE: Calendar sync start {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"mailbox:batch:retry-failed","memoryBeforeCommandInMb":60.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.883,"memoryPeakAfterCommandInMB":99.883} {"correlation_id":"d51071d5-ead0-45f0-a07e-e3234074f884","trace_id":"77173d9f-596f-405f-ae55-ba117b66455d"}
[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1393,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1393,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:16] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1393,"provider":"google","refreshToken":"5aa7e2d96b53201cd16fca5d2e4ef3ad03320971fc064781d18aee3ae7b99fbf","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1393,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Account has been deleted"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1393,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1387,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1387,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1387,"provider":"google","refreshToken":"8157ac6de94842937194009e9c50e459253600f799dacf6a40755ffdbeb5bba6","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1387,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Account has been deleted"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1387,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1348,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1348,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1348,"provider":"google","refreshToken":"9e7d13d3032d0cb1b79d8e95aef01383e8e91eb52ff8ee960c8a0b6b95cd8c73","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1348,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1348,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1361,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1361,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1361,"provider":"google","refreshToken":"6c843da199c2b9907445329304fcc4ec5057a4ee748d8299641764395c08e1fd","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1361,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Account has been deleted"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1361,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1310,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1310,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1310,"provider":"google","refreshToken":"e34818922c2830a660813a63f6169a4a9a992ae2cccd7dc8dd7796cfdb470ef1","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1310,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1310,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1333,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1333,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1333,"provider":"google","refreshToken":"6c902986546d8e8da1dc539b046cdc1d458f519acc972e5b5f1d6a1a295165e0","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1333,"provider":"google","responseBody":{"error":"unauthorized_client","error_description":"Unauthorized"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1333,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1368,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1368,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:17] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1368,"provider":"google","refreshToken":"d2f128898ff8543bd16b69cfae37896ab85119b0f5ed2b431d739593bb600333","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1368,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1368,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1365,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1365,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1365,"provider":"google","refreshToken":"7676e4a9afcd082b413248ab5ec6e487021fec6a9bdf315860a59cefad9caad8","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1365,"provider":"google","responseBody":{"error":"unauthorized_client","error_description":"Unauthorized"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1365,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1364,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1364,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1364,"provider":"google","refreshToken":"dd5882ebce76e645292ce33ae74238abbb77c0a4ecc6a2bfe723cad82e72ba8e","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1364,"provider":"google","responseBody":{"error":"unauthorized_client","error_description":"Unauthorized"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1364,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1370,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1370,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1370,"provider":"office","refreshToken":"b7ee8035306d0043cea6e00e7c4fe14f745e44074a1194db62a31cdf8b70af3e","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1370,"provider":"office","responseBody":"{\"error\":\"invalid_client\",\"error_description\":\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 41d8db5c-a91f-41a6-9b5c-22a6c99b9100 Correlation ID: 70bc0a6f-1565-4e74-94dc-419d94108fa9 Timestamp: 2026-05-28 08:28:18Z\",\"error_codes\":[7000215],\"timestamp\":\"2026-05-28 08:28:18Z\",\"trace_id\":\"41d8db5c-a91f-41a6-9b5c-22a6c99b9100\",\"correlation_id\":\"70bc0a6f-1565-4e74-94dc-419d94108fa9\",\"error_uri\":\"https://login.microsoftonline.com/error?code=7000215\"}"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1370,"provider":"office","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1202,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1202,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:18] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1202,"provider":"office","refreshToken":"b458799ccc29b21a6e2eb5260fdb63e49ccba21bf942a3973fb63799bd7f0afe","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1202,"provider":"office","responseBody":"{\"error\":\"invalid_client\",\"error_description\":\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: d3d14dfc-1b70-40c4-b9db-fab12f748300 Correlation ID: 4c5f746c-8366-44c1-8733-6877607826db Timestamp: 2026-05-28 08:28:19Z\",\"error_codes\":[7000215],\"timestamp\":\"2026-05-28 08:28:19Z\",\"trace_id\":\"d3d14dfc-1b70-40c4-b9db-fab12f748300\",\"correlation_id\":\"4c5f746c-8366-44c1-8733-6877607826db\",\"error_uri\":\"https://login.microsoftonline.com/error?code=7000215\"}"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1202,"provider":"office","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1502,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1502,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: Calendar sync job dispatched {"calendar_id":501} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1300,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1300,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1300,"provider":"google","refreshToken":"4b811db0725fd9602a95943519a7da935e2a5065da7d9ebfcb170752e3e1ddb8","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1300,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Account has been deleted"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1300,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1409,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1409,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1409,"provider":"google","refreshToken":"e2a3f2d06894894eed1ee87d9db1ace77d4d42ee6e1288a8940ad2c10333b0c4","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1409,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1409,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1352,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1352,"provider":"google"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1352,"provider":"google","refreshToken":"dd4b16b00fdc1216da6b717c02338c073636e29162826b2de6db3f064fc029eb","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1352,"provider":"google","responseBody":{"error":"invalid_grant","error_description":"Bad Request"}} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1352,"provider":"google","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1296,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1296,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:19] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1296,"provider":"office","refreshToken":"011ae723c9d800c674e0b4be76f49fc046dac7d501b66c59ef0d9549cfa56ae5","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1502,"provider":"google"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1502,"provider":"google"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [Calendar] Processing sync {"calendarId":"a33076c1-8d97-431a-99f0-85c9524e118b","from":null,"to":null,"delta":"CIiFh8TP44kDEIiFh8TP44kDGAUgkZvkzgIokZvkzgI=","last_sync":"2024-12-09 07:12:53","dateMode":"daily"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"integration-app","crm_owner":1695,"team_id":3143} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1502,"provider":"google"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1502,"provider":"google"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1296,"provider":"office","responseBody":"{\"error\":\"invalid_client\",\"error_description\":\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: dd83a147-95bc-407c-8c9b-3c14e7cb7d00 Correlation ID: bb16bae3-b3c4-467e-bd95-4e7ab85364c9 Timestamp: 2026-05-28 08:28:20Z\",\"error_codes\":[7000215],\"timestamp\":\"2026-05-28 08:28:20Z\",\"trace_id\":\"dd83a147-95bc-407c-8c9b-3c14e7cb7d00\",\"correlation_id\":\"bb16bae3-b3c4-467e-bd95-4e7ab85364c9\",\"error_uri\":\"https://login.microsoftonline.com/error?code=7000215\"}"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":1296,"provider":"office","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":391,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":391,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":391,"provider":"office","refreshToken":"00045eebae0f39b34887c6d53f92ae78064f7145e1f4b67754aebd03cfb2d881","state":"full-refresh"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.INFO: [Google Calendar] Failed to watch channel for calendar {"calendarId":"a33076c1-8d97-431a-99f0-85c9524e118b","code":400,"reason":"{
\"error\": {
\"errors\": [
{
\"domain\": \"global\",
\"reason\": \"push.webhookUrlNotHttps\",
\"message\": \"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\"
}
],
\"code\": 400,
\"message\": \"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\"
}
}"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:20] local.WARNING: [Calendar] Sync failed {"calendarId":"a33076c1-8d97-431a-99f0-85c9524e118b","code":400,"reason":"{
\"error\": {
\"errors\": [
{
\"domain\": \"global\",
\"reason\": \"push.webhookUrlNotHttps\",
\"message\": \"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\"
}
],
\"code\": 400,
\"message\": \"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\"
}
}"} {"correlation_id":"45e201e4-60d2-407c-ae71-13e4739c0875","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":391,"provider":"office","responseBody":"{\"error\":\"invalid_client\",\"error_description\":\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 587224ad-f597-4371-b2ba-00fcd2da1b00 Correlation ID: 4e752610-95b1-4606-847f-68e00f90be0a Timestamp: 2026-05-28 08:28:21Z\",\"error_codes\":[7000215],\"timestamp\":\"2026-05-28 08:28:21Z\",\"trace_id\":\"587224ad-f597-4371-b2ba-00fcd2da1b00\",\"correlation_id\":\"4e752610-95b1-4606-847f-68e00f90be0a\",\"error_uri\":\"https://login.microsoftonline.com/error?code=7000215\"}"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.ERROR: [SocialAccountService] Failed to refresh token {"socialAccountId":391,"provider":"office","reason":"Flow refresh required."} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1271,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1271,"provider":"office"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"498bfcf1-b82c-466d-8f91-2f3f1cdf980f","trace_id":"19e20da3-a204-446a-a01e-568f25ddd9fd"}
[2026-05-28 08:28:21] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1271,"provider":"office",...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
81661
|
2834
|
15
|
2026-05-28T08:35:30.445722+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779957330445_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-7635200922161528077
|
-4598385934329243181
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
iTerm2ShellEditViewSessionScriptsProfilesWindowHelp‹$0A-zshscreenpipe"DOCKER₴81DEV (docker)worker-calendar:worker-calendar_00:startedworker-conferences:worker-conferences_00: startedworker-crm-sync:worker-crm-sync_00: startedworker-crm-update:worker-crm-update_00: startedworker-download:worker-download_00:startedworker-emails:worker-emails_00:startedworker-es-update:worker-es-update_00:startedworker-nudges:worker-nudges_00: started₴2-zshО 84-zshWhat's next:Try Docker Debug forseamless, persistentdebugging tools in any container or image → docker debug docker_lamp_1Learnmoreat [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20915-fix-missing-header-text-relay) $csfixdocker exec -it docker_lamp_1•/vendor/bin/php-cs-fixer fix--config=.php-cs-fixer.dist.php-v--using-cache=no --diffPHP CS Fixer 3.95.1 Adalbertus by Fabien Potencier, Dariusz Ruminski and contributors.PHP runtime: 8.5.5Loaded config default from ".php-cs-fixer.dist.php".Running analysis on 7 cores with 10 files per process.5698/5698 C80100%*5ec2-user@ip-10-30-1...O 86100% <78• Thu 28 May 11:35:30181ec2-user@ip-10-30-140-...$7Fixed 0 of 5698 files in 52.731 seconds, 799.06 MB memory usedDetected deprecations in use (they will stop working in next major release):- Rule set"@PHP74Migration" is deprecated. Use"@PHP7x4Migration" instead.- Rule set "@PHP80Migration" is deprecated. Use "@PHP8x®Migration" instead.- Rule set "@PHP81Migration" is deprecated. Use "@PHP8x1Migration" instead.- Rule set "@PHP82Migration" is deprecated. Use "@PHP8x2Migration" instead.- Rule set "@PHP83Migration" is deprecated. Use "@PHP8x3Migration"instead.- Rule set "@PHP84Migration" is deprecated. Use "@PHP8x4Migration" instead.What's next:Try Docker Debug for seamless, persistent debugging tools in any container or image + docker debug docker_lamp_1Learn more at https://docs.docker.com/go/debug-cli/lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20915-fix-missing-header-text-relay) $D...
|
81659
|
NULL
|
NULL
|
NULL
|
|
81662
|
2835
|
21
|
2026-05-28T08:35:30.550992+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779957330550_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20915-fix-missing-header-text-relay, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09740692,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20915-fix-missing-header-text-relay","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8374335,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-7635200922161528077
|
-4598385934329243181
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20915-fix-missing-head Project: faVsco.js, menu
JY-20915-fix-missing-header-text-relay, menu
Start Listening for PHP Debug Connections
rapstomViewCoocKelucionRurTOOI-WindowFV faVsco.|s ~$ JY-20915-fix-mlproidetMpapi.ohopip console.phophp customer aol.ohophp emoedded.ohophp heaith.ohophp scim.ohophp woro ected-web.ohophp web ohopho wenhookohoseno'svsMadd→ damanar→[EMAIL]= custom.log= hubspot-journal-pollllogIdraveios<B phpunit.xmos tttisEoauth-private.keyE oauth-public.kevВА кoragoE supervisord.pidtext-relav.isoni tests> @n Feature> Ca Intearation> Ôa Services› En StubsvUniaActionsa componentaconticurationuconsoleiMcontractsleiniomainTettsatmsEventsMsycaotionMThrtutheD GuardsMHolnareD HttpMlintoarationeMlintoractianeMiloheheaYowelhe nomisKerodtoh© SyncMailbox.phpockhrhtt©TextReiayServiceTest.phgcass Textkelayservacu175pravate tuncczon asporcortentenv.ronnenttНананкРВВВВНВКЕВРВВВВВНВSnessage = Sservice-›users nessages-›get(Smailbox, Snessageld)Sheaders = Smessage-›getPayLoad->getHeaders®:sorzeanallo a nuetsco - nullforeach (Sheaders as Sheader)if (Sheader->name aa= "X-6n-Original-To') {sorzoznallo & sheader»>value} elseif (Sheader->nane aa= "To')oemesuersvallueSif (Sceciotent la= null) €Snatches = Sthis->natches axoectedbectintent Srecio tent, Sexoectedabins. Sexoectedhostsidsmatches)/I Sanitize Pll by renoving plus-tag content for loggingSsanitizedRecipient = explode( separator: "+', Srecipient) (0):Log: :info( message: "[TextRelayService) Refused message','message id' =› Snessageld,'orsoinal to saniitazed' 8 Scantitai zedRecsinhientreturn Smatches:Log::warning message:' (TextRelayService) Refused message: missing X-Gn-Original-To and To headers'."nessage id' => SmessageidDA} catch (Exception Se)Log::error( message: '(TextRelayService) Fafled to inspect message'. ("aessaoeo = smessage.oexcepczon = se->gechessage oentny?conuuraeycrodons"rerur thiteonivate function natchesEynectedPecinient(strina Srecinient strina SexoectedAlias. strina SexoectedHost)= booiA1A1S [IBAN]—214=21s216BEBCEВKhosean!=282233236238TEERORdBRBS100% 142-• Thu 28 May 11:35:30laravellog XSF jiminny@localhostA HS_local (jiminny@localhost& console (PROD.de console (EU)#COntOA STAGINGI12826-85-28 88:28:2211 10001,NOTTCE: Calendar sync end R"retrieved calendars":31,"processed calendars":3} 1"correlation_10*:~4980tCt1-082C-4660-8191-2+571C0tІУУIHIWWEIEMTONSO tAtORanGSTOnNano RACUNMeEONyLUSaCeon COnnanoIE MCOmmAnG MACa tANGAORSynO FE MAROnV:PLORA NORManO GHTIRCR:P(2026-05-28 08:28:22) Local. INFO:[SocialAccountService] Fetching token {"socialAccountId":1115,"provider":"google*} {"correlation_id*:*9436b8cd-f0cc-4ee2-805e-472888fd5928(2826-85-28 88:28:221 10c02, 7NF0:Sochau.ccountServ.celtoken retrrevedsocial.ccountidtaas"orovden"."aoog.ecorrelation.sd.9usco8cd--8cc-4002-8850-47788860597[2026-85-28 88:28:22)LencryptedTokenHanager, Generating access token. 1'mode":"Legacy"} 1"correlation_1d*: 9436b8cd-f8cc-4ee2-885e-472888f05928", "trace_1d : 19876-85-2 8332832211[Calendarl Processing sync (*calendarid*:*26760b6d-f860-427e-bf78-591e388e3cle" •fron"snult, "to":null,*delta*-*CJ x49033070EJ x49031070GAU W[2026-85-28 88:28:22] Loca2.WARNING: [Pipedrive) Account not connected for user ("userId":"e6538737-e704-455f-a37a-3e79b665a220", "account": (*Jininny| \Models| (SocialAccount"17876-85-28 8382882221Loco TEDK[CrnOwnerResolver) Integration ouner is not connected, attempting team members 1 crn_provider":"pipedrive", crn_owner":241,"tean_1d":19)[2026-05-28 08:28:22] Locar. INFO:[CrnOwnerResolver) No tean nenbers found with active cra connection 1"crm_provider":"pipedrive", "team_1d":19) 1"correlation_id":"9436b8cd-17826-85-28 88-2882221Loc0TNE0KEcononmerkesolvenlNo ream memben found mrthusetive com commectoionleem moysdenoinedo venem503092Leoma aoond""9LRohReds(2026-85-28 88:28:22] Zocal.WARNING: [Calendar) CRM disconnected for user so events will not be matched {"provider":"pipedrive", "user_id":241, "nessage": "Your Pipedrive acoSoczalAccountService) Fetching token {"socialAccount.d":1115, "provider":"google y 1"correlation_1d:*9436b8cd-f8cc-4002-885e-472888fd592:SoczalAccountService) Token retrieved {socialAccount.d":1115, "providen":"google"y 1"correlation_id*:*9436b8cd-f0cc-4002-885e-472888fd592[EncryptedTokenManager) Generating access token. {"node":"legacy"} {"cornelation_id": 943608cd-f0cc-4ce2-885c-472888fd5928", "trace_id":"19(2826-85-28 08:28:23) Loca2.INFO:Google Calendar) Failed to watch channel for calendar "calendarid":"2676cbod-f86c-427e-bf78-591e388e3cle*, "code":480,"reason":"*donainl*: \'global\*.message\": \*WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\*|"codel *: 499)|"nessagel *: |*WebHook callback nust be HTTPS:/webhook/calendar/coocle?resourceTvpezeventl}»} ("coccelatzion{₫":"9436b8сd~{8cс~4ee2-805e~4ỹ2888fđ5928"_"†cace…đ*•"19e28₫q3~о2ß4~446n~q81e~568f25₫₫đ9£g"](2826-85-28 88:28:231 10601, WARNING: [Calendanl Sunc fafled ("calendarid*:26760660-f86c-427e-bf78-5910388e301e\"reason\": \"push.webhookUrlNotHttps\",(Pnesange|": |-KebHook callback nust be HTTPS: /mebhook/callendar/coogle?nesounceTypezevent\*"codel": 489|"nossaael": |-HcbHook callback nust be HTTPS: /wehhook/calendar/aooale?cesounceTvpezeventle}*} {"correlation id:*9436b0cd-f0cc-4e62-805e-472888(d5928*, "trace id":*19e20da3-a204-446a~a01e-S68f25ddd9fd™)MANAHACTNR AR.DRODR AAA TNET(2026-05-28 08:28:23] Local. INFO:SocialAccountService) Token retrieved "socialAccountid":1421,"provider":"office" *correlation1d*:*82ba6688-7d5c-4789-9154-9918f63e2b:12826-85-28 88:28:23 Local.INF0: EncryptedTokenManager) Generating access token. :mode":"Leлacy") "connelation 2d:*82ba6688-7dSc-4789-9154-9918f63e2bfd*, "trace id":"1(2026-05-28 08:28:23) Local. INFO: [Calendar] Processing sync ('calendarid":"9e8b1a2c-1a8f-42bd-b161-810fc0baf540*, "fron":nutz, "to" :nutl, "delta":"ROusncdvaMuzCBYV8hguCBhf4uKAOnAHAGne ARIDRIRI NAA TuSArCAaalAnsAInt Comsnol CotAhind tAhon eeAAiSl AAAduntTAr:100 "nndlsdonkrThenAter TECAnnOlatIAnTRRICORhEARORTACA.1R0-01S/00196/260h.(2026-85-28 88:28:23] Local. INFO:menkras, ne gerneantll taant Tusor(2826-85-28 88:28:23] Local. INFO:mnank as, ne pecneantll taAnt TusorSocialAccountService) Token retrieved "socialAccountid":1499, "providen":"hubspot") "correlation 1d*:*82ba6688-7d5c-4789-9154-9918f63e2t[EncryptedTokenManager] Generating access token. ("node":"Legacy"} {"correlation id•OЛHARAдO, ПAGA MRO,015/001еЕторНЕни вслоло ЗаН,-Л0[CrnOwnerResolver) Integration ouner matched as CRM Ouner ("crm provider":"hubspot" "crn ouner":89, "tean id":2} ("correlation id":"82ba66:TMsnestonalondoalSiznainadnttz.cunc foc.dniinode/eonlnndnalilo loneliaos Aoes tabahhsa eanschinesineAeooootatzlon 2an.1О0hSseeEnank og, ne dechoroAAl TAAnt TuSOrJininny Console\Commands\Connand::run Memony usage before starting command {"conmand":"meeting-bot:schedule-bot" "memoryBeforeComnandInMb"Maankng, ne pechorogll TAAnt TusOr(ScheduleBotCommand) Dispatched activities to capture ("count":0} {"correlation id":*86a65984-a9f8-43c9-bBc3-1e9c8b4b9541" "trace id":*808(2826-85-28 88:29:851 10c02, INE0: Jfinfinnyl Consolel Cornands| Connandetrun Mesony usage fon connand ("cominerneeetnoaooscheouleetotrorstrorelonosnhoob.uenenonStr:kUhto%t4 spad...
|
81660
|
NULL
|
NULL
|
NULL
|
|
82982
|
2867
|
14
|
2026-05-28T09:59:23.719427+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779962363719_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
8243381250999052583
|
-8204424741936591934
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
SlackFileEditViewGoHistoryWindowHelpDOCKE!DOCKER881DEV (-zsh)О ₴2-zshscreenpipe"DOCKER (-zsh)2c55fe91ca4148a230e32eaa1865e" "$?") › '/dev/null' 2>&1 &docker_lamp_12026-05-28 09:13:57 Running ['artisan' jiminny:transcription:retry-fai] No failed transcriptionsdocker_lamp_1docker_lamp_125 Doting Hubpot journal polling service... Kdocker_lamp_11 '/usr/local/bin/php' 'artisan'jiminny:transcription:retry-failed >2>&1docker_lamp_12026-05-28 09:14:18 Running ['artisan'crm: reset-governor].......21docker_lamp_11 4 '/usr/local/bin/php' 'artisan'crm:reset-governor › '/proc/1/fd/1' 2:Gracefully Stopping...press Ctrl+C again to forceContainer docker-blackfire-1 StoppingContainer docker-mariadb-1 StoppingContainer kibana StoppingContainer docker_lamp_1 StoppingContainer docker-jiminny_ext-1 StoppingContainer ngrok StoppingContainer docker-datadog-1StoppingContainer docker-datadog-1StoppedContainer docker-blackfire-1 StoppedContainer kibana StoppedContainer elasticsearch StoppingContainer docker-jiminny_ext-1 StoppedContainer elasticsearch Stoppedmariadb-11 2026-05-28ownngrokpReq="{err: ‹nil>9:14:50 0 [Note] mariadbd (initiated by: unknown): Normal sht=2026-05-28T09:14:50+0000 lvl=info msg="received stop request" obj=apprestart:false}"2026-05-289:14:50 0 [Note] InnoDB: FTS optimize threadt=2026-05-28T09:14:50+0000 lvl=info msg="session closing" obj=tunnels.set=2026-05-28T09:14:50+0000 lvl=info msg="accept failed"obj=csess id=a35.err="reconnecting session closed"Container docker_lamp_1 ErrorError while StoppingContainer ngrok Error Error while StoppingContainer docker-mariadb-1 Error Error while Stoppingerror during connect: Post "[URL_WITH_CREDENTIALS] ~/jiminny/infrastructure/dev/docker (develop) $ED→HomeDMsActivityFilesLaterMore+Jiminny …..scnicrat# happy_birthday& infosec_internal_all# infra-changes# infrastructure_dev# jbu-team-info# jiminny-bg# platform-team# platform-tickets# product_launches# random# releases# support# thank-yous# the_people_of jimi...° Direct messages&o lliyana Netseva€. Vasil VasilevPetko KashinskiP. Galya Dimitrova&. Stefka Stoyanova&: Todor StamatovRo Steliyan Georgiev@ Ves8. MiraRio Nikolay YankovR. Stoyan Tomovdo James Graham100% C8• Thu 28 May 12:59:23Describe what you are looking for®# releases8 226 0• MessagesC Files• Bookmarks@ytunnyrappAaueaoy GitnuoToday ~CircleCI APP 11:16 MIVTDeployment Successful!+Project: appWhen:05/28/202608:16:27Tag:View JobGitHub APP12:27 PM3 new commits pushed to master by LakyLakda1cb1d1 - JY-20915 fix missing header71898ad0 - Merge branch 'master' into JY-20915-fix-missing-header-text-relaybc8d03d9 - Merge pull request #12136 fromjiminny/JY-20915-fix-missing-header-text-relayjiminny/app | Added by GitHubNewCircleCI APP 12:53 PMDeployment Successful!Project: appWhen:05/28/202609:53:14Tag:View JobMessage #releases+..•...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
82983
|
2868
|
30
|
2026-05-28T09:59:25.213770+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779962365213_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
rapstomCoocKetucioWindowFV faVsco.s ~i masterproid rapstomCoocKetucioWindowFV faVsco.s ~i masterproidetTextRelayService.php© InternetMessagelnterface.phcMaenanneiservice.orclass Textkelayservacu175phavare tuncczon aororcortentchvarohtentl©Textrekysewice.oned MeetingGeneratorda Notificationên OAuth2Dn Playbooks—KeCaLA—oeownyotaeeDn Streamingla Teama Telechony#UserPilotWebhookC Abstrac Semvice cho©ActivityProviderFactory.phpCActviysemce cno@ ApiResponseService.phpg conferenceService.phgclineehCaatswies donC InstantMeetingService.php@ IntercomService.phpC IpapiClient.phpServicas+,o,ct|vaaramssconsole:ovlminnucoon nosASAHHSllocallv Аpрорconsole 1s 363 mdvASTAGINGconsoleDockerSnessage = Sservice-›users nessages-›get(Smailbox, Snessageid):Sheaders = Smessage-›getPayLoad->getHeaders®:foreach (Sheaders as Sheader)if (Sheader->name aa= *X-6n-Original-Tcl) 4Smatches = Sthis->matchesExpectedRecipient(Sheader->valve, SexpectedALias, SexpectedHost)if (l Smatches) {// Sanitize PII by removing plus-tag content for loggingSsanitizedOriginalTo = explode( separator: *+*. Sheader->value) (01:wlexwewerwceKemuscomessade'message 1d' => Snessaceld)"origanalto_sanzcized a ssanzczzedurigznallo,rexurn Smarches:Log::warning( message:'[TextRelayService) Refused message: missing X-6n-Üriginal-To header', LOutputtid jiminny.text.relaysMorowtyTQREAGI uuid (UUID with tine-low a.gB enail provider Memail_provider_id v32412 62a417Sc-48cS-42fb-bd68-f18e3513461agsuite19e1447dea629ede32413 0793823с-6386-4729-6358-54304817651₫oswite19e172856932760832414 20801368-f896-4184-8716-368653786645osunte19e1c2e118addtfcXyLS co3325ch-1744-4256-9690-48428426668gsuite1902927868964642WlhwwathwnoekCorhodtr.cohoetacotherth.gsuiteHO0DAXXoRRonAMATOT MORNOR ThEToOn-OON TEEANITRANE.gsuite19e39beeff0bd19432418 e774986d-bb2a-4ac1-9932-b6b1a7ac885:qsuite19e3a7585c7eeScc32419 [CREDIT_CARD]-8157-09927754717419c3b1b038229cedyliel noan irscediyworeschhacohostyietyOSUITG19e6e922963d45A1enail sentat2026-65-10 23:45:162826-85-11 13:89:332826-85-12 12-33:482026-05-13 18:05:8nenkoetrk terteokDenANeRe AA.DRNA2826-85-18 89:48:322826-85-18 12:42-182826-85-28 12-54:40araieTtodayTashS0TO0У L7Thu 28 May 12:59:24custonuortaraveuiosA SF jiminny@localhostHS _Jocal jiminny@localhostconsole (PROD) X& console [EU,console (STAGING= 41415 A YN72a1111•734— 735 /FUВRTx: AutoSELECT * FROM cra_field_data foPlaygroundOo jiminny045 A1 A41 У66 ^sotn chisraetost on to.cheeeto dd = tazowUocoweUNTo.cewRosd.oWHERE activity_id = 79933459*ANU T.crsprovzoera1o = "пs-аcevaсy-сyрeйTs riuh acewttiessaoosSPleesexcreays where creareo.ar020-659517select * fron activities where user_ id YN (7160, 18608) and created at > *2826-85-22' order by id descaselect * sron users where team1d=and1d01N1018688,1364.168)select * fron actávities where usen id = 7168 order by sid deso0tt8select * fron accounts where team.1d a and nane = "coluenseselect * fron users where name Like "XSubrax"; # 31054, 111/select * from teans whereds12select * fron activity_searches where user_id = 31854)salleer +Ton servity casnehi ting hend setiuity searohoiiiie roisenderDE ZOETEN Scott <[EMAIL] Fowles «Kuliiit.FoulesallovdstistintelTioence.comCharles Beatty <cbeattyfbonhanandbrook.co.ukMantoGeongtey cnanto.acorghewsiinny.comsCavan Tomay cetavan tondwlthnhony caeyHOLDSWORTH Jason <[EMAIL]:OLIVER James <janes.ol/[EMAIL] Meoan <eegan.holnes0cemardostcanv.comukas Xovnult cukas.kouaidcntninny.comI recipient ustatusMeg Katsiouras <[EMAIL] Johnston Clark Linited <447782361298.467879332268.62x7XVJ82-8txt.Jininny.comsOroreSSeKevin Wal ken <447488488754.4478539384.e05 Xamo2lxminny.comsfafler447544084583.447893937879 ARDBABYARTEYETIMInnY.COonocesserMansa Connnsiow chmbozokueto ihittneelcer lleknynrondtyimonsdomnnAraceor"61485024454.61412457749.b2qZqBEDn79txt.iminny.com* <[EMAIL]{ Raza <[EMAIL]>processedLien Callaghan <447897828347.447841358164.8017M05k2P9txt.Sininny.concatch-al1[PHONE].359877878118.18oSkdKd2M0txt.jininnv.cororocosser¿4-01 code S200snul408snut?Coun208<nulCnutcnutN Wodsud Teams 187-58 UTE-R Ai/A enano...
|
NULL
|
-7394812089810624183
|
NULL
|
visual_change
|
ocr
|
NULL
|
rapstomCoocKetucioWindowFV faVsco.s ~i masterproid rapstomCoocKetucioWindowFV faVsco.s ~i masterproidetTextRelayService.php© InternetMessagelnterface.phcMaenanneiservice.orclass Textkelayservacu175phavare tuncczon aororcortentchvarohtentl©Textrekysewice.oned MeetingGeneratorda Notificationên OAuth2Dn Playbooks—KeCaLA—oeownyotaeeDn Streamingla Teama Telechony#UserPilotWebhookC Abstrac Semvice cho©ActivityProviderFactory.phpCActviysemce cno@ ApiResponseService.phpg conferenceService.phgclineehCaatswies donC InstantMeetingService.php@ IntercomService.phpC IpapiClient.phpServicas+,o,ct|vaaramssconsole:ovlminnucoon nosASAHHSllocallv Аpрорconsole 1s 363 mdvASTAGINGconsoleDockerSnessage = Sservice-›users nessages-›get(Smailbox, Snessageid):Sheaders = Smessage-›getPayLoad->getHeaders®:foreach (Sheaders as Sheader)if (Sheader->name aa= *X-6n-Original-Tcl) 4Smatches = Sthis->matchesExpectedRecipient(Sheader->valve, SexpectedALias, SexpectedHost)if (l Smatches) {// Sanitize PII by removing plus-tag content for loggingSsanitizedOriginalTo = explode( separator: *+*. Sheader->value) (01:wlexwewerwceKemuscomessade'message 1d' => Snessaceld)"origanalto_sanzcized a ssanzczzedurigznallo,rexurn Smarches:Log::warning( message:'[TextRelayService) Refused message: missing X-6n-Üriginal-To header', LOutputtid jiminny.text.relaysMorowtyTQREAGI uuid (UUID with tine-low a.gB enail provider Memail_provider_id v32412 62a417Sc-48cS-42fb-bd68-f18e3513461agsuite19e1447dea629ede32413 0793823с-6386-4729-6358-54304817651₫oswite19e172856932760832414 20801368-f896-4184-8716-368653786645osunte19e1c2e118addtfcXyLS co3325ch-1744-4256-9690-48428426668gsuite1902927868964642WlhwwathwnoekCorhodtr.cohoetacotherth.gsuiteHO0DAXXoRRonAMATOT MORNOR ThEToOn-OON TEEANITRANE.gsuite19e39beeff0bd19432418 e774986d-bb2a-4ac1-9932-b6b1a7ac885:qsuite19e3a7585c7eeScc32419 [CREDIT_CARD]-8157-09927754717419c3b1b038229cedyliel noan irscediyworeschhacohostyietyOSUITG19e6e922963d45A1enail sentat2026-65-10 23:45:162826-85-11 13:89:332826-85-12 12-33:482026-05-13 18:05:8nenkoetrk terteokDenANeRe AA.DRNA2826-85-18 89:48:322826-85-18 12:42-182826-85-28 12-54:40araieTtodayTashS0TO0У L7Thu 28 May 12:59:24custonuortaraveuiosA SF jiminny@localhostHS _Jocal jiminny@localhostconsole (PROD) X& console [EU,console (STAGING= 41415 A YN72a1111•734— 735 /FUВRTx: AutoSELECT * FROM cra_field_data foPlaygroundOo jiminny045 A1 A41 У66 ^sotn chisraetost on to.cheeeto dd = tazowUocoweUNTo.cewRosd.oWHERE activity_id = 79933459*ANU T.crsprovzoera1o = "пs-аcevaсy-сyрeйTs riuh acewttiessaoosSPleesexcreays where creareo.ar020-659517select * fron activities where user_ id YN (7160, 18608) and created at > *2826-85-22' order by id descaselect * sron users where team1d=and1d01N1018688,1364.168)select * fron actávities where usen id = 7168 order by sid deso0tt8select * fron accounts where team.1d a and nane = "coluenseselect * fron users where name Like "XSubrax"; # 31054, 111/select * from teans whereds12select * fron activity_searches where user_id = 31854)salleer +Ton servity casnehi ting hend setiuity searohoiiiie roisenderDE ZOETEN Scott <[EMAIL] Fowles «Kuliiit.FoulesallovdstistintelTioence.comCharles Beatty <cbeattyfbonhanandbrook.co.ukMantoGeongtey cnanto.acorghewsiinny.comsCavan Tomay cetavan tondwlthnhony caeyHOLDSWORTH Jason <[EMAIL]:OLIVER James <janes.ol/[EMAIL] Meoan <eegan.holnes0cemardostcanv.comukas Xovnult cukas.kouaidcntninny.comI recipient ustatusMeg Katsiouras <[EMAIL] Johnston Clark Linited <447782361298.467879332268.62x7XVJ82-8txt.Jininny.comsOroreSSeKevin Wal ken <447488488754.4478539384.e05 Xamo2lxminny.comsfafler447544084583.447893937879 ARDBABYARTEYETIMInnY.COonocesserMansa Connnsiow chmbozokueto ihittneelcer lleknynrondtyimonsdomnnAraceor"61485024454.61412457749.b2qZqBEDn79txt.iminny.com* <[EMAIL]{ Raza <[EMAIL]>processedLien Callaghan <447897828347.447841358164.8017M05k2P9txt.Sininny.concatch-al1[PHONE].359877878118.18oSkdKd2M0txt.jininnv.cororocosser¿4-01 code S200snul408snut?Coun208<nulCnutcnutN Wodsud Teams 187-58 UTE-R Ai/A enano...
|
NULL
|
NULL
|
NULL
|
NULL
|